home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / BARNET / INTERNET / PGP / PGP263I / pgp263i / src / c / pgp < prev    next >
Encoding:
Text File  |  1997-05-23  |  85.8 KB  |  3,040 lines

  1. /* #define TEMP_VERSION /* if defined, temporary experimental
  2.                        version of PGP */
  3. /* pgp.c -- main module for PGP.
  4.    PGP: Pretty Good(tm) Privacy - public key cryptography for the masses.
  5.  
  6.    Synopsis:  PGP uses public-key encryption to protect E-mail.
  7.    Communicate securely with people you've never met, with no secure
  8.    channels needed for prior exchange of keys.  PGP is well featured and
  9.    fast, with sophisticated key management, digital signatures, data
  10.    compression, and good ergonomic design.
  11.  
  12.    The original PGP version 1.0 was written by Philip Zimmermann, of
  13.    Phil's Pretty Good(tm) Software.  Many parts of later versions of
  14.    PGP were developed by an international collaborative effort,
  15.    involving a number of contributors, including major efforts by:
  16.    Branko Lankester <branko@hacktic.nl>
  17.    Hal Finney <74076.1041@compuserve.com>
  18.    Peter Gutmann <pgut1@cs.aukuni.ac.nz>
  19.    Other contributors who ported or translated or otherwise helped include:
  20.    Jean-loup Gailly in France
  21.    Hugh Kennedy in Germany
  22.    Lutz Frank in Germany
  23.    Cor Bosman in The Netherlands
  24.    Felipe Rodriquez Svensson in The Netherlands
  25.    Armando Ramos in Spain
  26.    Miguel Angel Gallardo Ortiz in Spain
  27.    Harry Bush and Maris Gabalins in Latvia
  28.    Zygimantas Cepaitis in Lithuania
  29.    Alexander Smishlajev
  30.    Peter Suchkow and Andrew Chernov in Russia
  31.    David Vincenzetti in Italy
  32.    ...and others.
  33.  
  34.  
  35.    (c) Copyright 1990-1996 by Philip Zimmermann.  All rights reserved.
  36.    The author assumes no liability for damages resulting from the use
  37.    of this software, even if the damage results from defects in this
  38.    software.  No warranty is expressed or implied.
  39.  
  40.    Note that while most PGP source modules bear Philip Zimmermann's
  41.    copyright notice, many of them have been revised or entirely written
  42.    by contributors who frequently failed to put their names in their
  43.    code.  Code that has been incorporated into PGP from other authors
  44.    was either originally published in the public domain or is used with
  45.    permission from the various authors.
  46.  
  47.    PGP is available for free to the public under certain restrictions.
  48.    See the PGP User's Guide (included in the release package) for
  49.    important information about licensing, patent restrictions on
  50.    certain algorithms, trademarks, copyrights, and export controls.
  51.  
  52.  
  53.    Philip Zimmermann may be reached at:
  54.    Boulder Software Engineering
  55.    3021 Eleventh Street
  56.    Boulder, Colorado 80304  USA
  57.    (303) 541-0140  (voice or FAX)
  58.    email:  prz@acm.org
  59.  
  60.  
  61.    PGP will run on MSDOS, Sun Unix, VAX/VMS, Ultrix, Atari ST,
  62.    Commodore Amiga, and OS/2.  Note:  Don't try to do anything with
  63.    this source code without looking at the PGP User's Guide.
  64.  
  65.    PGP combines the convenience of the Rivest-Shamir-Adleman (RSA)
  66.    public key cryptosystem with the speed of fast conventional
  67.    cryptographic algorithms, fast message digest algorithms, data
  68.    compression, and sophisticated key management.  And PGP performs
  69.    the RSA functions faster than most other software implementations.
  70.    PGP is RSA public key cryptography for the masses.
  71.  
  72.    Uses RSA Data Security, Inc. MD5 Message Digest Algorithm
  73.    as a hash for signatures.  Uses the ZIP algorithm for compression.
  74.    Uses the ETH IPES/IDEA algorithm for conventional encryption.
  75.  
  76.    PGP generally zeroes its used stack and memory areas before exiting.
  77.    This avoids leaving sensitive information in RAM where other users
  78.    could find it later.  The RSA library and keygen routines also
  79.    sanitize their own stack areas.  This stack sanitizing has not been
  80.    checked out under all the error exit conditions, when routines exit
  81.    abnormally.  Also, we must find a way to clear the C I/O library
  82.    file buffers, the disk buffers, and cache buffers.
  83.  
  84.    Revisions:
  85.    Version 1.0 -  5 Jun 91
  86.    Version 1.4 - 19 Jan 92
  87.    Version 1.5 - 12 Feb 92
  88.    Version 1.6 - 24 Feb 92
  89.    Version 1.7 - 29 Mar 92
  90.    Version 1.8 - 23 May 92
  91.    Version 2.0 -  2 Sep 92
  92.    Version 2.1 -  6 Dec 92
  93.    Version 2.2 -  6 Mar 93
  94.    Version 2.3 - 13 Jun 93
  95.    Version 2.3a-  1 Jul 93
  96.    Version 2.4 -  6 Nov 93
  97.    Version 2.5 -  5 May 94
  98.    Version 2.6 - 22 May 94
  99.    Version 2.6.1 - 29 Aug 94
  100.    Version 2.6.2 - 11 Oct 94
  101.    Version 2.6.2i - 7 May 95
  102.    Version 2.6.3(i) - 18 Jan 96
  103.    Version 2.6.3(i)a - 4 Mar 96
  104.  
  105.  */
  106.  
  107.  
  108. #include <ctype.h>
  109. #ifndef AMIGA
  110. #include <signal.h>
  111. #endif
  112. #include <stdio.h>
  113. #include <stdlib.h>
  114. #include <string.h>
  115.  
  116. #ifdef UNIX
  117. #include <sys/types.h>
  118. #include <sys/stat.h>
  119. #endif
  120.  
  121. #include "system.h"
  122. #include "mpilib.h"
  123. #include "random.h"
  124. #include "crypto.h"
  125. #include "fileio.h"
  126. #include "keymgmt.h"
  127. #include "language.h"
  128. #include "pgp.h"
  129. #include "exitpgp.h"
  130. #include "charset.h"
  131. #include "getopt.h"
  132. #include "config.h"
  133. #include "keymaint.h"
  134. #include "keyadd.h"
  135. #include "rsaglue.h"
  136. #include "noise.h"
  137.  
  138. #ifdef MACTC5
  139. #include "Macutil.h"
  140. #include "Macutil2.h"
  141. #include "Macutil3.h"
  142. #include "Macutil4.h"
  143. #include "Macbinary.h"
  144. #include "Binhex.h"
  145. #include "MacPGP.h"
  146. #include "mystr.h"
  147. void AddOutputFiles(char *filepath);
  148. void ReInitKeyMaint(void);
  149. extern char appPathName[];
  150. void         ReInitGlobals(void);
  151. extern int level,method;
  152. extern Boolean explicit_plainfile;
  153. extern long infile_line;
  154. extern int eofonce;
  155. extern boolean savedwashed;
  156. extern char *special;
  157. char *Outputfile = NULL;
  158. void check_expiration_date(void);
  159. #define BEST -1
  160. #define exit Exit
  161. void Exit(int x);
  162. #endif
  163.  
  164. #ifdef  M_XENIX
  165. char *strstr();
  166. long time();
  167. #endif
  168.  
  169. #ifdef MSDOS
  170. #ifdef __ZTC__            /* Extend stack for Zortech C */
  171. unsigned _stack_ = 24 * 1024;
  172. #endif
  173. #ifdef __TURBOC__
  174. unsigned _stklen = 24 * 1024;
  175. #endif
  176. #endif
  177. #define    STACK_WIPE    4096
  178.  
  179. #ifdef AMIGA
  180. #ifdef __SASC_60
  181. /* Let the compiler allocate us an appropriate stack. */
  182. extern long __stack = 32768L;
  183. #endif
  184.  
  185.  /* Add the appropriate AmigaOS version string, depending on the
  186.   * compiler flags.
  187.   */
  188. #ifdef USA
  189. static const char __DOSVer[] = "$VER: PGP 2.6.3a (04.03.96)"
  190. #  ifdef _M68020
  191.         " Amiga 68020 version by Rob Knop <rknop@mop.caltech.edu>";
  192. #  else
  193.         " Amiga 68000 version by Rob Knop <rknop@mop.caltech.edu>";
  194. #  endif
  195. #else
  196. static const char __DOSVer[] = "$VER: PGP 2.6.3ia (04.03.96)"
  197. #  ifdef _M68020
  198.         " Amiga 68020 version by Peter Simons <simons@peti.rhein.de>";
  199. #  else
  200.         " Amiga 68000 version by Peter Simons <simons@peti.rhein.de>";
  201. #  endif
  202. #endif /* USA */
  203. #endif /* AMIGA */
  204.  
  205. /* Global filenames and system-wide file extensions... */
  206. #ifdef USA
  207. char rel_version[] = _LANG("2.6.3a");    /* release version */
  208. #else
  209. char rel_version[] = _LANG("2.6.3ia");    /* release version */
  210. #endif
  211. char rel_date[] = "1996-03-04";        /* release date */
  212. /* gjm:
  213.  * RISC OS uses / not . for extensions, so...
  214.  */
  215. #ifdef RISC_OS
  216. char PGP_EXTENSION[] = "/pgp";
  217. char ASC_EXTENSION[] = "/asc";
  218. char SIG_EXTENSION[] = "/sig";
  219. char BAK_EXTENSION[] = "/bak";
  220. static char HLP_EXTENSION[] = "/hlp";
  221. #else
  222. char PGP_EXTENSION[] = ".pgp";
  223. char ASC_EXTENSION[] = ".asc";
  224. char SIG_EXTENSION[] = ".sig";
  225. char BAK_EXTENSION[] = ".bak";
  226. static char HLP_EXTENSION[] = ".hlp";
  227. #endif
  228. char CONSOLE_FILENAME[] = "_CONSOLE";
  229. #ifdef MACTC5
  230. char HELP_FILENAME[256] = "pgp.hlp";
  231. /* gjm:
  232.  * again, RISC OS uses / not .
  233.  */
  234. #elif defined(RISC_OS)
  235. char HELP_FILENAME[] = "pgp/hlp";
  236. #else
  237. static char HELP_FILENAME[] = "pgp.hlp";
  238. #endif
  239.  
  240. /* These files use the environmental variable PGPPATH as a default path: */
  241. char globalPubringName[MAX_PATH];
  242. char globalSecringName[MAX_PATH];
  243. char globalRandseedName[MAX_PATH];
  244. char globalCommentString[128];
  245.  
  246. /* Flags which are global across the driver code files */
  247. boolean verbose = FALSE;    /* -l option: display maximum information */
  248. FILE *pgpout;            /* Place for routine messages */
  249. /* gjm:
  250.  * This determines the way in which names are truncated under RISC OS:
  251.  */
  252. #ifdef RISC_OS
  253. int gjm_maxlen=10;
  254. #endif
  255.  
  256. static void usage(void);
  257. static void key_usage(void);
  258. static void arg_error(void);
  259. static void initsigs(void);
  260. static int do_keyopt(char);
  261. static int do_decrypt(char *);
  262. static void do_armorfile(char *);
  263. char ** ParseRecipients(char **);
  264. void hashpass (char *keystring, int keylen, byte *hash);
  265.  
  266. /* Various compression signatures: PKZIP, Zoo, GIF, Arj, and HPACK.
  267.    Lha(rc) is handled specially in the code; it is missing from the
  268.    compressSig structure intentionally.  If more formats are added,
  269.    put them before lharc to keep the code consistent.
  270.  
  271.    27-Jun-95 simons@peti.rhein.de (Peter Simons)
  272.    Added support for lh5 archive as generated by Lha. Unfortunately,
  273.    lh5 requires special treatment also. I inserted the check right
  274.    _before_ lharc, because lh5/lha is a special type of an lharc
  275.    archive.
  276.  */
  277. static char *compressSig[] =
  278. {"PK\03\04", "ZOO ", "GIF8", "\352\140", "Rar!",
  279.  "HPAK", "\037\213", "\037\235", "\032\013", "\032HP%"
  280.     /* lharc is special, must be last */ };
  281. static char *compressName[] =
  282. {"PKZIP", "Zoo", "GIF", "Arj", "RAR",
  283.  "Hpack", "gzip", "compressed", "PAK", "Hyper",
  284.  "Lha", "Lharc"};
  285. static char *compressExt[] =
  286. /* gjm:
  287.  * RISC OS extensions are, of course, different.
  288.  */
  289. #ifdef RISC_OS
  290. {"/zip", "/zoo", "/gif", "/arj", "/rar",
  291.  "/hpk", "/gz", "/Z", "/pak", "/hyp",
  292.  "/lha", "/lzh"};
  293. #else
  294. {".zip", ".zoo", ".gif", ".arj", ".rar",
  295.  ".hpk", ".gz", ".Z", ".pak", ".hyp",
  296.  ".lha", ".lzh"};
  297. #endif
  298. /* "\032\0??", "ARC", ".arc" */
  299.  
  300. /* Returns file signature type from a number of popular compression formats
  301.    or -1 if no match */
  302. int compressSignature(byte * header)
  303. {
  304.     int i;
  305.  
  306.     for (i = 0; i < sizeof(compressSig) / sizeof(*compressSig); i++)
  307.     if (!strncmp((char *) header, compressSig[i], strlen(compressSig[i])))
  308.         return i;
  309.  
  310.     /* Special check for lha files */
  311.     if (!strncmp((char *)header+2, "-lh5-", 5))
  312.       return i;
  313.  
  314.     /* Special check for lharc files */
  315.     if (header[2] == '-' && header[3] == 'l' &&
  316.     (header[4] == 'z' || header[4] == 'h') &&
  317.     header[6] == '-')
  318.     return i+1;
  319.     return -1;
  320. }                /* compressSignature */
  321.  
  322. /* returns TRUE if file is likely to be compressible */
  323. static boolean file_compressible(char *filename)
  324. {
  325.     byte header[8];
  326.     get_header_info_from_file(filename, header, 8);
  327.     if (compressSignature(header) >= 0)
  328.     return FALSE;        /* probably not compressible */
  329.     return TRUE;        /* possibly compressible */
  330. }                /* compressible */
  331.  
  332.  
  333. /* Possible error exit codes - not all of these are used.  Note that we
  334.    don't use the ANSI EXIT_SUCCESS and EXIT_FAILURE.  To make things
  335.    easier for compilers which don't support enum we use #defines */
  336.  
  337. #define EXIT_OK                0
  338. #define INVALID_FILE_ERROR        1
  339. #define FILE_NOT_FOUND_ERROR        2
  340. #define UNKNOWN_FILE_ERROR        3
  341. #define NO_BATCH            4
  342. #define BAD_ARG_ERROR            5
  343. #define INTERRUPT            6
  344. #define OUT_OF_MEM            7
  345.  
  346. /* Keyring errors: Base value = 10 */
  347. #define KEYGEN_ERROR            10
  348. #define NONEXIST_KEY_ERROR        11
  349. #define KEYRING_ADD_ERROR        12
  350. #define KEYRING_EXTRACT_ERROR        13
  351. #define KEYRING_EDIT_ERROR        14
  352. #define KEYRING_VIEW_ERROR        15
  353. #define KEYRING_REMOVE_ERROR        16
  354. #define KEYRING_CHECK_ERROR        17
  355. #define KEY_SIGNATURE_ERROR        18
  356. #define KEYSIG_REMOVE_ERROR        19
  357.  
  358. /* Encode errors: Base value = 20 */
  359. #define SIGNATURE_ERROR            20
  360. #define RSA_ENCR_ERROR            21
  361. #define ENCR_ERROR            22
  362. #define COMPRESS_ERROR            23
  363.  
  364. /* Decode errors: Base value = 30 */
  365. #define SIGNATURE_CHECK_ERROR        30
  366. #define RSA_DECR_ERROR            31
  367. #define DECR_ERROR            32
  368. #define DECOMPRESS_ERROR        33
  369.  
  370.  
  371. #ifdef SIGINT
  372.  
  373. /* This function is called if a BREAK signal is sent to the program.  In this
  374.    case we zap the temporary files.
  375.  */
  376. void breakHandler(int sig)
  377. {
  378. #ifdef UNIX
  379.     if (sig == SIGPIPE) {
  380.     signal(SIGPIPE, SIG_IGN);
  381.     exitPGP(INTERRUPT);
  382.     }
  383.     if (sig != SIGINT)
  384.     fprintf(stderr, "\nreceived signal %d\n", sig);
  385.     else
  386. #endif
  387.     fprintf(pgpout, LANG("\nStopped at user request\n"));
  388.     exitPGP(INTERRUPT);
  389. }
  390. #endif
  391.  
  392. /* Clears screen and homes the cursor. */
  393. static void clearscreen(void)
  394. {
  395.     fprintf(pgpout, "\n\033[0;0H\033[J\r           \r");  /* ANSI sequence. */
  396.     fflush(pgpout);
  397. }
  398.  
  399. /* We had to process the config file first to possibly select the
  400.    foreign language to translate the sign-on line that follows... */
  401. static void signon_msg(void)
  402. {
  403.     word32 tstamp;
  404.     /* display message only once to allow calling multiple times */
  405.     static boolean printed = FALSE;
  406.  
  407.     if (quietmode || printed)
  408.     return;
  409.     printed = TRUE;
  410.     fprintf(stderr,
  411. LANG("Pretty Good Privacy(tm) %s - Public-key encryption for the masses.\n"),
  412.         rel_version);
  413. #ifdef TEMP_VERSION
  414.     fputs(
  415. "Internal development version only - not for general release.\n", stderr);
  416. #endif
  417.     fputs(LANG("(c) 1990-96 Philip Zimmermann, Phil's Pretty Good Software."),
  418.     stderr);
  419.     fprintf(stderr, " %s\n",LANG(rel_date));
  420. /* gjm:
  421.  * So that everyone knows whom to blame ...
  422.  */
  423. #ifdef RISC_OS
  424.     fputs("(RISC OS version by Gareth McCaughan, May 1997)\n",stderr);
  425. #endif
  426. #ifdef USA
  427.     fputs(LANG(signon_legalese), stderr);
  428. #endif
  429.     fputs(
  430. #ifdef USA
  431. LANG("Export of this software may be restricted by the U.S. government.\n"),
  432. #else
  433. LANG("International version - not for use in the USA. Does not use RSAREF.\n"),
  434. #endif
  435.       stderr);
  436.  
  437.     get_timestamp((byte *) & tstamp);    /* timestamp points to tstamp */
  438.     fprintf(pgpout, LANG("Current time: %s\n"), ctdate(&tstamp));
  439. }
  440.  
  441.  
  442. #ifdef TEMP_VERSION        /* temporary experimental version of PGP */
  443. #include <time.h>
  444. #define CREATION_DATE 0x30FE3640ul
  445.                 /* CREATION_DATE is
  446.                    Thu Jan 18, 1996 1200 hours UTC */
  447. #define LIFESPAN    ((unsigned long) 60L * (unsigned long) 86400L)
  448.                 /* LIFESPAN is 60 days */
  449.  
  450. /* If this is an experimental version of PGP, cut its life short */
  451. void check_expiration_date(void)
  452. {
  453.     if (get_timestamp(NULL) > (CREATION_DATE + LIFESPAN)) {
  454.     fprintf(stderr,
  455.         "\n\007This experimental version of PGP has expired.\n");
  456.     exit(-1);        /* error exit */
  457.     }
  458. }                /* check_expiration_date */
  459. #else                /* no expiration date */
  460. #define check_expiration_date()    /* null statement */
  461. #endif                /* TEMP_VERSION */
  462.  
  463. /* -f means act as a unix-style filter */
  464. /* -i means internalize extended file attribute information, only supported
  465.  *          between like (or very compatible) operating systems. */
  466. /* -l means show longer more descriptive diagnostic messages */
  467. /* -m means display plaintext output on screen, like unix "more" */
  468. /* -d means decrypt only, leaving inner signature wrapping intact */
  469. /* -t means treat as pure text and convert to canonical text format */
  470.  
  471. /* Used by getopt function... */
  472. #define OPTIONS "abcdefghiklmo:prstu:vwxz:ABCDEFGHIKLMO:PRSTU:VWX?"
  473. extern int optind;
  474. extern char *optarg;
  475.  
  476. #define INCLUDE_MARK "-@"
  477. #define INCLUDE_MARK_LEN sizeof(INCLUDE_MARK)-1    /* skip the \0 */
  478.  
  479. boolean emit_radix_64 = FALSE;    /* set by config file */
  480. static boolean sign_flag = FALSE;
  481. boolean moreflag = FALSE;
  482. boolean filter_mode = FALSE;
  483. static boolean preserve_filename = FALSE;
  484. static boolean decrypt_only_flag = FALSE;
  485. static boolean de_armor_only = FALSE;
  486. static boolean strip_sig_flag = FALSE;
  487. boolean clear_signatures = TRUE;
  488. boolean strip_spaces;
  489. static boolean c_flag = FALSE;
  490. static boolean u_flag = FALSE;        /* Did I get my_name from -u? */
  491. boolean encrypt_to_self = FALSE; /* should I encrypt messages to myself? */
  492. boolean sign_new_userids = TRUE;
  493. boolean batchmode = FALSE;    /* if TRUE: don't ask questions */
  494. boolean quietmode = FALSE;
  495. boolean force_flag = FALSE;    /* overwrite existing file without asking */
  496. #ifdef VMS            /* kludge for those stupid VMS variable-length
  497.                    text records */
  498. char literal_mode = MODE_TEXT;    /* MODE_TEXT or MODE_BINARY for literal
  499.                    packet */
  500. #else                /* not VMS */
  501. char literal_mode = MODE_BINARY; /* MODE_TEXT or MODE_BINARY for literal
  502.                     packet */
  503. #endif                /* not VMS */
  504. /* my_name is substring of default userid for secret key to make signatures */
  505. char my_name[256] = "\0";    /* null my_name means take first userid
  506.                    in ring */
  507. boolean keepctx = FALSE;    /* TRUE means keep .ctx file on decrypt */
  508. /* Ask for each key separately if it should be added to the keyring */
  509. boolean interactive_add = FALSE;
  510. boolean compress_enabled = TRUE; /* attempt compression before encryption */
  511. long timeshift = 0L;        /* seconds from GMT timezone */
  512. int version_byte = VERSION_BYTE_NEW;
  513. boolean nomanual = 0;
  514. /* If non-zero, initialize file to this many random bytes */
  515. int makerandom = 0;
  516.  
  517.  
  518. static char *outputfile = NULL;
  519. #ifndef MACTC5
  520. static int errorLvl = EXIT_OK;
  521. #else
  522. int errorLvl = EXIT_OK;
  523. #endif
  524. static char mcguffin[256];    /* userid search tag */
  525. boolean signature_checked = FALSE;
  526. int checksig_pass = 0;
  527. boolean use_charset_header;
  528. char charset_header[16] = "";
  529. char plainfile[MAX_PATH];
  530. int myArgc = 2;
  531. char **myArgv;
  532. struct hashedpw *passwds = 0, *keypasswds = 0;
  533. static struct hashedpw **passwdstail = &passwds;
  534.  
  535. #ifdef MACTC5
  536. extern unsigned long PGPStart, WNECalls;
  537.  
  538. void ReInitGlobals()
  539. {
  540.     int i;
  541.     char scratch[64];
  542.     WNECalls = 0;
  543.     if (verbose)
  544.         PGPStart = TickCount();
  545.     else
  546.         PGPStart = 0;
  547.     Abort = FALSE;
  548.     BreakCntl = 0;
  549.     pgpout = stderr;
  550.     optind = 1;
  551.     errorLvl = EXIT_OK;
  552.     myArgc = 2;
  553.     myArgv = nil;
  554.     emit_radix_64 = FALSE;        /* set by config file */
  555.     sign_flag = FALSE;
  556.     moreflag = FALSE;
  557.     filter_mode = FALSE;
  558.     preserve_filename = FALSE;
  559.     decrypt_only_flag = FALSE;
  560.     de_armor_only = FALSE;
  561.     strip_sig_flag = FALSE;
  562.     u_flag = FALSE;
  563.     c_flag = FALSE;
  564.     signature_checked = FALSE;
  565.     literal_mode = MODE_BINARY;    /* MODE_TEXT or MODE_BINARY for literal packet */
  566.     errorLvl = EXIT_OK;
  567.     outputfile = Outputfile;
  568.     method = BEST;     /* one of BEST, DEFLATE (only), or STORE (only) */
  569.     level = 9;        /* 0=fastest compression, 9=best compression */
  570.     special = NULL;    /* List of special suffixes */
  571.     infile_line = 0;
  572.     eofonce = 0;
  573.     savedwashed = FALSE;
  574.     ReInitKeyMaint();
  575.     settmpdir(nil);
  576.     setoutdir(nil);
  577.     makerandom = 0;
  578.     if (xcli_opt[0]) {
  579.         if (argv[argc] == nil)
  580.             argv[argc] = malloc((size_t) 80);
  581.         if (argv[argc] == nil) {
  582.             BailoutAlert(LANG("Out of memory"));
  583.             ExitToShell();
  584.         }
  585.         strcpy(argv[argc], xcli_opt);
  586.         argc++;
  587.         fprintf(pgpout, "         %s\n", xcli_opt);
  588.     }
  589.     for (i = 0; i <= 63; i++)
  590.         scratch[i] = to_upper(xcli_opt[i]);
  591.     if (strcmp(xcli_opt, "+NOMANUAL=ON")==0) nomanual = true;
  592.     else nomanual = false;
  593.  }
  594.  
  595. int init_pgp()
  596. {
  597.     int err=0;
  598.     pgpout=stderr;
  599.     /* Process the config file first.  Any command-line arguments will
  600.        override the config file settings */
  601.     buildfilename( mcguffin, "config.txt");
  602.     if ( processConfigFile( mcguffin ) < 0 )
  603.         err=BAD_ARG_ERROR;
  604.     init_charset();
  605.     signon_msg();
  606.     g_armor_flag=emit_radix_64;
  607.     g_text_mode=(literal_mode == MODE_TEXT);
  608.     g_clear_signatures=clear_signatures;
  609.     PGPSetFinfo(globalRandseedName,'RSed','MPGP');
  610.     set_precision(MAX_UNIT_PRECISION);
  611.     return err;
  612. }
  613.  
  614.  
  615. void Exit(int x) {
  616.  
  617.     errorLvl = x;
  618.     if (myArgv)
  619.         free(myArgv);
  620.     if (mcguffins)
  621.         free(mcguffins);
  622.     mac_cleanup_tmpf();
  623.     longjmp(jmp_env,5);
  624. }
  625.  
  626.  
  627. int pgp_dispatch(int argc, char *argv[])
  628. {
  629.     int status, opt;
  630.     char *inputfile = NULL;
  631.     char **recipient = NULL;
  632. /*    char **mcguffins;   zigf made global so we can free */
  633.     boolean macbin_flag = FALSE;
  634. #else
  635.  
  636. int main(int argc, char *argv[])
  637. {
  638.     int status, opt;
  639.     char *inputfile = NULL;
  640.     char **recipient = NULL;
  641.     char **mcguffins;
  642. #endif /* MACTC5 */
  643.     char *workfile, *tempf;
  644.     boolean nestflag = FALSE;
  645.     boolean decrypt_mode = FALSE;
  646.     boolean wipeflag = FALSE;
  647.     boolean armor_flag = FALSE;    /* -a option */
  648.     boolean separate_signature = FALSE;
  649.     boolean keyflag = FALSE;
  650.     boolean encrypt_flag = FALSE;
  651.     boolean conventional_flag = FALSE;
  652.     boolean attempt_compression; /* attempt compression before encryption */
  653.     boolean output_stdout;    /* Output goes to stdout */
  654.     char *clearfile = NULL;
  655.     char *literal_file = NULL;
  656.     char literal_file_name[MAX_PATH];
  657.     char cipherfile[MAX_PATH];
  658.     char keychar = '\0';
  659.     char *p;
  660.     byte ctb;
  661.     struct hashedpw *hpw;
  662.  
  663.     /* Initial messages to stderr */
  664.     pgpout = stderr;
  665.  
  666. #ifdef MACTC5
  667.     ReInitGlobals();
  668. #endif
  669. #ifdef    DEBUG1
  670.     verbose = TRUE;
  671. #endif
  672.     /* The various places one can get passwords from.
  673.      * We accumulate them all into two lists.  One is
  674.      * to try on keys only, and is stored in no particular
  675.      * order, while the other is of unknown purpose so
  676.      * far (they may be used for conventional encryption
  677.      * or decryption as well), and are kept in a specific
  678.      * order.  If any password in the general list is found
  679.      * to decode a key, it is moved to the key list.
  680.      * The general list is not grown after initialization,
  681.      * so the tail pointer is not used after this.
  682.      */
  683.  
  684. #ifndef MACTC5
  685.     if ((p = getenv("PGPPASS")) != NULL) {
  686.     hpw = xmalloc(sizeof(struct hashedpw));
  687.     hashpass(p, strlen(p), hpw->hash);
  688.     /* Add to linked list of key passwords */
  689.     hpw->next = keypasswds;
  690.     keypasswds = hpw;
  691.     }
  692.     /* The -z "password" option should be used instead of PGPPASS if
  693.      * the environment can be displayed with the ps command (eg. BSD).
  694.      * If the system does not allow overwriting of the command line
  695.      * argument list but if it has a "hidden" environment, PGPPASS
  696.      * should be used.
  697.      */
  698.     for (opt = 1; opt < argc; ++opt) {
  699.     p = argv[opt];
  700.     if (p[0] != '-' || p[1] != 'z')
  701.         continue;
  702.     /* Accept either "-zpassword" or "-z password" */
  703.     p += 2;
  704.     if (!*p)
  705.         p = argv[++opt];
  706.     /* p now points to password */
  707.     if (!p)
  708.         break;        /* End of arg list - ignore */
  709.     hpw = xmalloc(sizeof(struct hashedpw));
  710.     hashpass(p, strlen(p), hpw->hash);
  711.     /* Wipe password */
  712.     while (*p)
  713.         *p++ = ' ';
  714.     /* Add to tail of linked list of passwords */
  715.     hpw->next = 0;
  716.     *passwdstail = hpw;
  717.     passwdstail = &hpw->next;
  718.     }
  719.     /*
  720.      * If PGPPASSFD is set in the environment try to read the password
  721.      * from this file descriptor.  If you set PGPPASSFD to 0 pgp will
  722.      * use the first line read from stdin as password.
  723.      */
  724.     if ((p = getenv("PGPPASSFD")) != NULL) {
  725.     int passfd;
  726.     if (*p && (passfd = atoi(p)) >= 0) {
  727.         char pwbuf[256];
  728.         p = pwbuf;
  729. /* gjm:
  730.  * It's unlikely that any RISC OS user will try to use PGPPASSFD.
  731.  * If they do, they'll find that it sort of works; but in RISC OS
  732.  * |stdin| and friends don't have fd's (=handles).
  733.  * If |passfd==0| then the user probably wants |stdin|, so we
  734.  * check specially for that.
  735.  */
  736. #ifdef RISC_OS
  737.         if (passfd==0)
  738.         while (fread(p,1,1,stdin)==1 && *p != '\n') ++p;
  739.         else
  740. #endif
  741.         while (read(passfd, p, 1) == 1 && *p != '\n')
  742.         ++p;
  743.         hpw = xmalloc(sizeof(struct hashedpw));
  744.         hashpass(pwbuf, p - pwbuf, hpw->hash);
  745.         memset(pwbuf, 0, p - pwbuf);
  746.         /* Add to tail of linked list of passwords */
  747.         hpw->next = 0;
  748.         *passwdstail = hpw;
  749.         passwdstail = &hpw->next;
  750.     }
  751.     }
  752.     /* Process the config file.  The following override each other:
  753.        - Hard-coded defaults
  754.        - The system config file
  755.        - Hard-coded defaults for security-critical things
  756.        - The user's config file
  757.        - Environment variables
  758.        - Command-line options.
  759.      */
  760.     opt = 0;            /* Number of config files read */
  761. #ifdef PGP_SYSTEM_DIR
  762. #ifdef UNIX
  763.     buildsysfilename(mcguffin, ".pgprc");
  764.     if (access(mcguffin, 0) != 0)
  765. #endif
  766. /* gjm:
  767.  * RISC OS uses / not . for extensions.
  768.  */
  769. #ifdef RISC_OS
  770.     buildsysfilename(mcguffin, "config/txt");
  771. #else
  772.     buildsysfilename(mcguffin, "config.txt");
  773. #endif
  774.     if (access(mcguffin, 0) == 0) {
  775.     opt++;
  776.     /*
  777.      * Note: errors here are NOT fatal, so that people
  778.      * can use PGP with a corrputed system file.
  779.      */
  780.     processConfigFile(mcguffin);
  781.     }
  782. #endif
  783.  
  784.     /*
  785.      * These must be personal; the system config file may not
  786.      * influence them.
  787.      */
  788. /* gjm:
  789.  * Of course the following names need to be different for RISC OS.
  790.  * Unfortunately they're too long for ordinary use, so we use
  791.  * mangled versions. However, if the envariable PGP$LongConfNames
  792.  * is set at startup then we use longer versions.
  793.  */
  794. #ifdef RISC_OS
  795.     if (getenv("PGP$LongConfNames")!=NULL) {
  796.     buildfilename(globalPubringName, "pubring/pgp");
  797.     buildfilename(globalSecringName, "secring/pgp");
  798.     buildfilename(globalRandseedName, "randseed/bin");
  799.     }
  800.     else {
  801.     buildfilename(globalPubringName, "pubrng/pgp");
  802.     buildfilename(globalSecringName, "secrng/pgp");
  803.     buildfilename(globalRandseedName, "randsd/bin");
  804.     }
  805. #else
  806.     buildfilename(globalPubringName, "pubring.pgp");
  807.     buildfilename(globalSecringName, "secring.pgp");
  808.     buildfilename(globalRandseedName, "randseed.bin");
  809. #endif
  810.     my_name[0] = '\0';
  811.  
  812.     /* Process the config file first.  Any command-line arguments will
  813.        override the config file settings */
  814. #if defined(UNIX) || defined(MSDOS) || defined(OS2) || defined (WIN32)
  815.     /* Try "pgp.ini" on MS-DOS or ".pgprc" on Unix */
  816. #ifdef UNIX
  817.     buildfilename(mcguffin, ".pgprc");
  818. #else
  819.     buildfilename(mcguffin, "pgp.ini");
  820. #endif
  821.     if (access(mcguffin, 0) != 0)
  822.     buildfilename(mcguffin, "config.txt");
  823. #else
  824. /* gjm:
  825.  * As usual, dots turn into slashes.
  826.  */
  827. #ifdef RISC_OS
  828.     buildfilename(mcguffin, "config/txt");
  829. #else
  830.     buildfilename(mcguffin, "config.txt");
  831. #endif
  832. #endif
  833.     if (access(mcguffin, 0) == 0) {
  834.     opt++;
  835.     if (processConfigFile(mcguffin) < 0)
  836.         exit(BAD_ARG_ERROR);
  837.     }
  838.     if (!opt)
  839.     fprintf(pgpout, LANG("\007No configuration file found.\n"));
  840.  
  841.     init_charset();
  842. #endif /* MACTC5 */
  843.  
  844. #ifdef MSDOS            /* only on MSDOS systems */
  845.     if ((p = getenv("TZ")) == NULL || *p == '\0') {
  846.     fprintf(pgpout,LANG("\007WARNING: Environmental variable TZ is not \
  847. defined, so GMT timestamps\n\
  848. may be wrong.  See the PGP User's Guide to properly define TZ\n\
  849. in AUTOEXEC.BAT file.\n"));
  850.     }
  851. #endif                /* MSDOS */
  852.  
  853. #ifdef VMS
  854. #define TEMP "SYS$SCRATCH"
  855. #else
  856. #define TEMP "TMP"
  857. #endif                /* VMS */
  858.     if ((p = getenv(TEMP)) != NULL && *p != '\0')
  859.     settmpdir(p);
  860.  
  861.     if ((myArgv = (char **) malloc((argc + 2) * sizeof(char **))) == NULL) {
  862.     fprintf(stderr, LANG("\n\007Out of memory.\n"));
  863.     exitPGP(7);
  864.     }
  865.     myArgv[0] = NULL;
  866.     myArgv[1] = NULL;
  867.  
  868. /* gjm:
  869.  * Filename length limits on RISC OS vary from one filesystem
  870.  * to another. So, if the envariable PGP$MaxLength is set to
  871.  * a sensible numeric value, we use that. (Default is 10.)
  872.  */
  873. #ifdef RISC_OS
  874.     {   char *s = getenv("PGP$MaxLength");
  875.         int m   = s ? atoi(s) : 10;
  876.         if (m<10) m=10;
  877.         else if (m>=MAX_PATH) m=MAX_PATH-1;
  878.         gjm_maxlen=m;
  879.     }
  880. #endif
  881.  
  882.     /* Process all the command-line option switches: */
  883.     while (optind < argc) {
  884.     /*
  885.      * Allow random order of options and arguments (like GNU getopt)
  886.      * NOTE: this does not work with GNU getopt, use getopt.c from
  887.      * the PGP distribution.
  888.      */
  889.     if ((!strncmp(argv[optind], INCLUDE_MARK, INCLUDE_MARK_LEN)) ||
  890.            ((opt = pgp_getopt(argc, argv, OPTIONS)) == EOF)) {
  891.         if (optind == argc)    /* -- at end */
  892.         break;
  893.         myArgv[myArgc++] = argv[optind++];
  894.         continue;
  895.     }
  896.     opt = to_lower(opt);
  897.     if (keyflag && (keychar == '\0' || (keychar == 'v' && opt == 'v'))) {
  898.         if (keychar == 'v')
  899.         keychar = 'V';
  900.         else
  901.         keychar = opt;
  902.         continue;
  903.     }
  904.     switch (opt) {
  905.     case 'a':
  906.         armor_flag = TRUE;
  907.         emit_radix_64 = 1;
  908.         break;
  909.     case 'b':
  910.         separate_signature = strip_sig_flag = TRUE;
  911.         break;
  912.     case 'c':
  913.         encrypt_flag = conventional_flag = TRUE;
  914.         c_flag = TRUE;
  915.         break;
  916.     case 'd':
  917.         decrypt_only_flag = TRUE;
  918.         break;
  919.     case 'e':
  920.         encrypt_flag = TRUE;
  921.         break;
  922. #ifdef MACTC5
  923.     case 'f':
  924.         if (macbin_flag == FALSE) filter_mode = TRUE;
  925.         break;
  926. #else
  927.     case 'f':
  928.         filter_mode = TRUE;
  929.         break;
  930. #endif
  931.     case '?':
  932.     case 'h':
  933.         usage();
  934.         break;
  935. #ifdef VMS
  936.     case 'i':
  937.         literal_mode = MODE_LOCAL;
  938.         break;
  939. #else
  940. #ifdef MACTC5
  941.     case 'i':
  942.         macbin_flag = TRUE;
  943.         moreflag = FALSE;
  944.         literal_mode = MODE_BINARY;
  945.         filter_mode = FALSE;
  946.         break;
  947. #endif /* MACTC5 */
  948. #endif                /* VMS */
  949.     case 'k':
  950.         keyflag = TRUE;
  951.         break;
  952.     case 'l':
  953.         verbose = TRUE;
  954.         break;
  955. #ifdef MACTC5
  956.     case 'm':
  957.         if( macbin_flag == FALSE )
  958.             moreflag = TRUE;
  959.         break;
  960. #else
  961.     case 'm':
  962.         moreflag = TRUE;
  963.         break;
  964. #endif
  965.     case 'p':
  966.         preserve_filename = TRUE;
  967.         break;
  968.     case 'o':
  969.         outputfile = optarg;
  970.         break;
  971.     case 's':
  972.         sign_flag = TRUE;
  973.         break;
  974. #ifdef MACTC5
  975.     case 't':
  976.         if( macbin_flag == FALSE )
  977.             literal_mode = MODE_TEXT;
  978.         break;
  979. #else
  980.     case 't':
  981.         literal_mode = MODE_TEXT;
  982.         break;
  983. #endif
  984.     case 'u':
  985.         strncpy(my_name, optarg, sizeof(my_name) - 1);
  986.         CONVERT_TO_CANONICAL_CHARSET(my_name);
  987.         u_flag = TRUE;
  988.         break;
  989.     case 'w':
  990.         wipeflag = TRUE;
  991.         break;
  992.     case 'z':
  993.         break;
  994.         /* '+' special option: does not require - */
  995.     case '+':
  996.         if (processConfigLine(optarg) == 0) {
  997.                 if (!strncmp(optarg,"CH",2)) /* CHARSET */
  998.                     init_charset();
  999.         break;
  1000.         }
  1001.         fprintf(stderr, "\n");
  1002.         /* fallthrough */
  1003.     default:
  1004.         arg_error();
  1005.     }
  1006.     }
  1007.     myArgv[myArgc] = NULL;    /* Just to make it NULL terminated */
  1008.  
  1009.     if (keyflag && keychar == '\0')
  1010.     key_usage();
  1011.  
  1012.     signon_msg();
  1013.     check_expiration_date();    /* hobble any experimental version */
  1014.  
  1015.     /*
  1016.      * Write to stdout if explicitly asked to, or in filter mode and
  1017.      * no explicit file name was given.
  1018.      */
  1019.     output_stdout = outputfile ? strcmp(outputfile, "-")  == 0 : filter_mode;
  1020.  
  1021. #if 1
  1022.     /* At request of Peter Simons, use stderr always. Sounds reasonable. */
  1023.     /* JIS: Put this code back in... removing it broke too many things */
  1024.     if (!output_stdout)
  1025.     pgpout = stdout;
  1026. #endif
  1027.  
  1028.  
  1029. #if defined(UNIX) || defined(VMS)
  1030.     umask(077);            /* Make files default to private */
  1031. #endif
  1032.  
  1033.     initsigs();            /* Catch signals */
  1034.     noise();            /* Start random number generation */
  1035.  
  1036.     if (keyflag) {
  1037.     status = do_keyopt(keychar);
  1038.     if (status < 0)
  1039.         user_error();
  1040.     exitPGP(status);
  1041.     }
  1042.     /* -db means break off signature certificate into separate file */
  1043.     if (decrypt_only_flag && strip_sig_flag)
  1044.     decrypt_only_flag = FALSE;
  1045.  
  1046.     if (decrypt_only_flag && armor_flag)
  1047.     decrypt_mode = de_armor_only = TRUE;
  1048.  
  1049.     if (outputfile != NULL)
  1050.     preserve_filename = FALSE;
  1051.  
  1052.     if (!sign_flag && !encrypt_flag && !conventional_flag && !armor_flag) {
  1053.     if (wipeflag) {        /* wipe only */
  1054.         if (myArgc != 3)
  1055.         arg_error();    /* need one argument */
  1056.         if (wipefile(myArgv[2]) == 0 && remove(myArgv[2]) == 0) {
  1057.         fprintf(pgpout,
  1058.             LANG("\nFile %s wiped and deleted. "), myArgv[2]);
  1059.         fprintf(pgpout, "\n");
  1060.         exitPGP(EXIT_OK);
  1061.         } else if (file_exists(myArgv[2]))
  1062.             fprintf(pgpout,
  1063. LANG("\n\007Error: Can't wipe out file '%s' - read only, maybe?\n"),
  1064.                         myArgv[2]);
  1065.             else {
  1066.             fprintf(pgpout,
  1067.                 LANG("\n\007File '%s' does not exist.\n"), myArgv[2]);
  1068.         }
  1069.         exitPGP(UNKNOWN_FILE_ERROR);
  1070.     }
  1071.     /* decrypt if none of the -s -e -c -a -w options are specified */
  1072.     decrypt_mode = TRUE;
  1073.     }
  1074.     if (myArgc == 2) {        /* no arguments */
  1075. #ifdef UNIX
  1076.     if (!filter_mode && !isatty(fileno(stdin))) {
  1077.         /* piping to pgp without arguments and no -f:
  1078.          * switch to filter mode but don't write output to stdout
  1079.          * if it's a tty, use the preserved filename */
  1080.         if (!moreflag)
  1081.         pgpout = stderr;
  1082.         filter_mode = TRUE;
  1083.         if (isatty(fileno(stdout)) && !moreflag)
  1084.         preserve_filename = TRUE;
  1085.     }
  1086. #endif
  1087.     if (!filter_mode) {
  1088.         if (quietmode) {
  1089.         quietmode = FALSE;
  1090.         signon_msg();
  1091.         }
  1092.         fprintf(pgpout,
  1093. LANG("\nFor details on licensing and distribution, see the PGP User's Guide.\
  1094. \nFor other cryptography products and custom development services, contact:\
  1095. \nPhilip Zimmermann, 3021 11th St, Boulder CO 80304 USA, \
  1096. phone +1 303 541-0140\n"));
  1097.         if (strcmp((p = LANG("@translator@")), "@translator@"))
  1098.         fprintf(pgpout, p);
  1099.         fprintf(pgpout, LANG("\nFor a usage summary, type:  pgp -h\n"));
  1100. #ifdef MACTC5
  1101.         exitPGP(BAD_ARG_ERROR);
  1102. #else
  1103.         exit(BAD_ARG_ERROR);    /* error exit */
  1104. #endif
  1105.     }
  1106.     } else {
  1107.     if (filter_mode) {
  1108.         recipient = &myArgv[2];
  1109.     } else {
  1110.         inputfile = myArgv[2];
  1111.         recipient = &myArgv[3];
  1112.     }
  1113.     recipient = ParseRecipients(recipient);
  1114.     }
  1115.  
  1116.  
  1117.     if (filter_mode) {
  1118.     inputfile = "stdin";
  1119.     } else if (makerandom > 0) {    /* Create the input file */
  1120.     /*
  1121.      * +makerandom=<bytes>: Create an input file consisting of <bytes>
  1122.      * cryptographically strong random bytes, before applying the
  1123.      * encryption options of PGP.  This is an advanced option, so
  1124.      * assume the user knows what he's doing and don't bother about
  1125.      * overwriting questions.  E.g.
  1126.      * pgp +makerandom=24 foofile
  1127.      *    Create "foofile" with 24 random bytes in it.
  1128.      * pgp +makerandom=24 -ea foofile recipient
  1129.      *    The same, but also encrypt it to "recipient", creating
  1130.      *    foofile.asc as well.
  1131.      * This feature was created to allow PGP to create and send keys
  1132.      * around for other applications to use.
  1133.      */
  1134.     status = cryptRandWriteFile(inputfile, (struct IdeaCfbContext *)0,
  1135.                            (unsigned)makerandom);
  1136.     if (status < 0) {
  1137.         fprintf(stderr,"Error writing file \"%s\"\n",inputfile);
  1138.         exitPGP(INVALID_FILE_ERROR);
  1139.     }
  1140.     fprintf(pgpout, LANG("File %s created containing %d random bytes.\n"),
  1141.         inputfile, makerandom);
  1142.     /* If we aren't encrypting, don't bother trying to decrypt this! */
  1143.     if (decrypt_mode)
  1144.         exitPGP(EXIT_OK);
  1145.  
  1146.     /* This is obviously NOT a text file */
  1147.     literal_mode = MODE_BINARY;
  1148.     } else {
  1149.     if (decrypt_mode && no_extension(inputfile)) {
  1150.         strcpy(cipherfile, inputfile);
  1151.         force_extension(cipherfile, ASC_EXTENSION);
  1152.         if (file_exists(cipherfile)) {
  1153.         inputfile = cipherfile;
  1154.         } else {
  1155.         force_extension(cipherfile, PGP_EXTENSION);
  1156.         if (file_exists(cipherfile)) {
  1157.             inputfile = cipherfile;
  1158.         } else {
  1159.             force_extension(cipherfile, SIG_EXTENSION);
  1160.             if (file_exists(cipherfile))
  1161.             inputfile = cipherfile;
  1162.         }
  1163.         }
  1164.     }
  1165.     if (!file_exists(inputfile)) {
  1166.         fprintf(pgpout,
  1167.             LANG("\n\007File '%s' does not exist.\n"), inputfile);
  1168.         errorLvl = FILE_NOT_FOUND_ERROR;
  1169.         user_error();
  1170.     }
  1171.     }
  1172.  
  1173.     if (strlen(inputfile) >= (unsigned) MAX_PATH - 4) {
  1174.     fprintf(pgpout,
  1175.         LANG("\007Invalid filename: '%s' too long\n"), inputfile);
  1176.     errorLvl = INVALID_FILE_ERROR;
  1177.     user_error();
  1178.     }
  1179.     strcpy(plainfile, inputfile);
  1180.  
  1181.     if (filter_mode) {
  1182.     setoutdir(NULL);    /* NULL means use tmpdir */
  1183.     } else {
  1184.     if (outputfile)
  1185.         setoutdir(outputfile);
  1186.     else
  1187.         setoutdir(inputfile);
  1188.     }
  1189.  
  1190.     if (filter_mode) {
  1191.     workfile = tempfile(TMP_WIPE | TMP_TMPDIR);
  1192.     readPhantomInput(workfile);
  1193.     } else {
  1194.     workfile = inputfile;
  1195.     }
  1196.  
  1197.     get_header_info_from_file(workfile, &ctb, 1);
  1198.     if (decrypt_mode) {
  1199.     strip_spaces = FALSE;
  1200.     if (!is_ctb(ctb) && is_armor_file(workfile, 0L))
  1201.         do_armorfile(workfile);
  1202.     else if (do_decrypt(workfile) < 0)
  1203.         user_error();
  1204. #ifdef MACTC5
  1205.     if (verbose) fprintf(stderr, "Final file = %s.\n", plainfile);
  1206.     /* Allow for overide of auto-unmacbin : 205b */
  1207.     if( (macbin_flag == FALSE) && is_macbin(plainfile) )
  1208.         bin2mac(plainfile,TRUE);
  1209.     else {
  1210.         AddOutputFiles(plainfile);
  1211.         PGPSetFinfo(plainfile,FType,FCreator);
  1212.     }
  1213.     if (use_clipboard) File2Scrap(plainfile);
  1214. #endif
  1215.     if (batchmode && !signature_checked)
  1216.         exitPGP(1);        /* alternate success, file did not have sig. */
  1217.     else
  1218.         exitPGP(EXIT_OK);
  1219.     }
  1220.     /*
  1221.      * See if plaintext input file was actually created by PGP earlier--
  1222.      * If it was, maybe we should NOT encapsulate it in a literal packet.
  1223.      * (nestflag = TRUE).  Otherwise, always encapsulate it (default).
  1224.      * (Why test for filter_mode???)
  1225.      */
  1226.     if (!batchmode && !filter_mode && legal_ctb(ctb)) {
  1227.     /*      Special case--may be a PGP-created packet, so
  1228.        do we inhibit encapsulation in literal packet? */
  1229.     fprintf(pgpout,
  1230. LANG("\n\007Input file '%s' looks like it may have been created by PGP. "),
  1231.         inputfile);
  1232.     fprintf(pgpout,
  1233. LANG("\nIs it safe to assume that it was created by PGP (y/N)? "));
  1234.     nestflag = getyesno('n');
  1235.     } else if (force_flag && makerandom == 0 && legal_ctb(ctb)) {
  1236.     nestflag = TRUE;
  1237.     }
  1238.  
  1239.     if (moreflag && makerandom == 0) {
  1240.     /* special name to cause printout on decrypt */
  1241.     strcpy(literal_file_name, CONSOLE_FILENAME);
  1242.     literal_mode = MODE_TEXT;    /* will check for text file later */
  1243.     } else {
  1244.     strcpy(literal_file_name, file_tail(inputfile));
  1245. #ifdef MSDOS
  1246.     strlwr(literal_file_name);
  1247. #endif
  1248.     }
  1249.     literal_file = literal_file_name;
  1250.  
  1251.     /*      Make sure non-text files are not accidentally converted
  1252.        to canonical text.  This precaution should only be followed
  1253.        for US ASCII text files, since European text files may have
  1254.        8-bit character codes and still be legitimate text files
  1255.        suitable for conversion to canonical (CR/LF-terminated)
  1256.        text format. */
  1257.     if (literal_mode == MODE_TEXT && !is_text_file(workfile)) {
  1258.     fprintf(pgpout,
  1259. LANG("\nNote: '%s' is not a pure text file.\n\
  1260. File will be treated as binary data.\n"),
  1261.         workfile);
  1262.     literal_mode = MODE_BINARY;    /* now expect straight binary */
  1263.     }
  1264.     if (moreflag && literal_mode == MODE_BINARY) {
  1265.     /* For eyes only?  Can't display binary file. */
  1266.     fprintf(pgpout,
  1267. LANG("\n\007Error: Only text files may be sent as display-only.\n"));
  1268.     errorLvl = INVALID_FILE_ERROR;
  1269.     user_error();
  1270.     }
  1271.  
  1272.     /*
  1273.      * See if plainfile looks like it might be incompressible,
  1274.      * by examining its contents for compression headers for
  1275.      * commonly-used compressed file formats like PKZIP, etc.
  1276.      * Remember this information for later, when we are deciding
  1277.      * whether to attempt compression before encryption.
  1278.      *
  1279.      * Naturally, don't bother if we are making a separate signature or
  1280.      * clear-signed message.  Also, don't bother trying to compress a
  1281.      * PGP message, as it's probably already compressed.
  1282.      */
  1283.     attempt_compression = compress_enabled && !separate_signature &&
  1284.                           !nestflag && !clearfile && makerandom == 0 &&
  1285.                           file_compressible(plainfile);
  1286.  
  1287. #ifdef MACTC5
  1288.     if(( macbin_flag == TRUE ) && (nestflag==FALSE)) {
  1289.         char *saveworkfile;
  1290.         nestflag = false;
  1291.         saveworkfile = workfile;
  1292.         workfile = tempfile(TMP_WIPE|TMP_TMPDIR);
  1293.         if (mac2bin(saveworkfile, workfile)!=0) {
  1294.             fprintf(pgpout, LANG("\n\007Error: MacBinary failed!\n"));
  1295.             errorLvl = INVALID_FILE_ERROR;
  1296.             rmtemp(workfile);
  1297.             exitPGP(errorLvl);
  1298.         }
  1299.     }
  1300. #endif
  1301.     if (sign_flag) {
  1302.     if (!filter_mode && !quietmode)
  1303.         fprintf(pgpout,
  1304. LANG("\nA secret key is required to make a signature. "));
  1305.     if (!quietmode && my_name[0] == '\0') {
  1306.         fprintf(pgpout,
  1307. LANG("\nYou specified no user ID to select your secret key,\n\
  1308. so the default user ID and key will be the most recently\n\
  1309. added key on your secret keyring.\n"));
  1310.     }
  1311.     strip_spaces = FALSE;
  1312.     clearfile = NULL;
  1313.     if (literal_mode == MODE_TEXT) {
  1314.         /* Text mode requires becoming canonical */
  1315.         tempf = tempfile(TMP_WIPE | TMP_TMPDIR);
  1316.         /* +clear means output file with signature in the clear,
  1317.            only in combination with -t and -a, not with -e or -b */
  1318.         if (!encrypt_flag && !separate_signature &&
  1319.         emit_radix_64 && clear_signatures) {
  1320.         clearfile = workfile;
  1321.         strip_spaces = TRUE;
  1322.         }
  1323.         make_canonical(workfile, tempf);
  1324.         if (!clearfile)
  1325.         rmtemp(workfile);
  1326.         workfile = tempf;
  1327.     }
  1328.     if (attempt_compression || encrypt_flag || emit_radix_64 ||
  1329.         output_stdout)
  1330.         tempf = tempfile(TMP_WIPE | TMP_TMPDIR);
  1331.     else
  1332.         tempf = tempfile(TMP_WIPE);
  1333.     /* for clear signatures we create a separate signature */
  1334.     status = signfile(nestflag, separate_signature || (clearfile != NULL),
  1335.            my_name, workfile, tempf, literal_mode, literal_file);
  1336.     rmtemp(workfile);
  1337.     workfile = tempf;
  1338.  
  1339.     if (status < 0) {    /* signfile failed */
  1340.         fprintf(pgpout, LANG("\007Signature error\n"));
  1341.         errorLvl = SIGNATURE_ERROR;
  1342.         user_error();
  1343.     }
  1344.     } else if (!nestflag) {    /* !sign_file */
  1345.     /*      Prepend CTB_LITERAL byte to plaintext file.
  1346.        --sure wish this pass could be optimized away. */
  1347.     if (attempt_compression || encrypt_flag || emit_radix_64 ||
  1348.         output_stdout)
  1349.         tempf = tempfile(TMP_WIPE | TMP_TMPDIR);
  1350.     else
  1351.         tempf = tempfile(TMP_WIPE);
  1352.     /* for clear signatures we create a separate signature */
  1353.     status = make_literal(workfile, tempf, literal_mode, literal_file);
  1354.     rmtemp(workfile);
  1355.     workfile = tempf;
  1356.     }
  1357.  
  1358.     if (encrypt_flag) {
  1359.         if (emit_radix_64 || output_stdout)
  1360.         tempf = tempfile(TMP_WIPE | TMP_TMPDIR);
  1361.     else
  1362.         tempf = tempfile(TMP_WIPE);
  1363.     if (!conventional_flag) {
  1364.         if (!filter_mode && !quietmode)
  1365.         fprintf(pgpout,
  1366. LANG("\n\nRecipients' public key(s) will be used to encrypt. "));
  1367.         if (recipient == NULL || *recipient == NULL ||
  1368.         **recipient == '\0') {
  1369.         /* no recipient specified on command line */
  1370.         fprintf(pgpout,
  1371. LANG("\nA user ID is required to select the recipient's public key. "));
  1372.         fprintf(pgpout, LANG("\nEnter the recipient's user ID: "));
  1373. #ifdef AMIGA
  1374.                 requesterdesc=LANG("\nEnter the recipient's user ID: ");
  1375. #endif
  1376.         getstring(mcguffin, 255, TRUE);        /* echo keyboard */
  1377.         if ((mcguffins = (char **) malloc(2 * sizeof(char *))) == NULL)
  1378.         {
  1379.             fprintf(stderr, LANG("\n\007Out of memory.\n"));
  1380.             exitPGP(7);
  1381.         }
  1382.         mcguffins[0] = mcguffin;
  1383.         mcguffins[1] = "";
  1384.         } else {
  1385.         /* recipient specified on command line */
  1386.         mcguffins = recipient;
  1387.         }
  1388.         for (recipient = mcguffins; *recipient != NULL &&
  1389.          **recipient != '\0'; recipient++) {
  1390.         CONVERT_TO_CANONICAL_CHARSET(*recipient);
  1391.         }
  1392.         status = encryptfile(mcguffins, workfile, tempf,
  1393.                  attempt_compression);
  1394.     } else {
  1395.         status = idea_encryptfile(workfile, tempf, attempt_compression);
  1396.     }
  1397.  
  1398.     rmtemp(workfile);
  1399.     workfile = tempf;
  1400.  
  1401.     if (status < 0) {
  1402.         fprintf(pgpout, LANG("\007Encryption error\n"));
  1403.         errorLvl = (conventional_flag ? ENCR_ERROR : RSA_ENCR_ERROR);
  1404.         user_error();
  1405.     }
  1406.     } else if (attempt_compression && !separate_signature && !clearfile) {
  1407.     /*
  1408.      * PGP used to be parsimonious about compression; originally, it only
  1409.      * did it for files that were being encrypted (to reduce the
  1410.      * redundancy in the plaintext), but it should really do it for
  1411.      * anything where it's not a bad idea.
  1412.      */
  1413.         if (emit_radix_64 || output_stdout)
  1414.         tempf = tempfile(TMP_WIPE | TMP_TMPDIR);
  1415.     else
  1416.         tempf = tempfile(TMP_WIPE);
  1417.     squish_file(workfile, tempf);
  1418.     rmtemp(workfile);
  1419.     workfile = tempf;
  1420.     }
  1421.  
  1422.     /*
  1423.      * Write to stdout if explicitly asked to, or in filter mode and
  1424.      * no explicit file name was given.
  1425.      */
  1426.     if (output_stdout) {
  1427.     if (emit_radix_64) {
  1428.         /* NULL for outputfile means write to stdout */
  1429.         if (armor_file(workfile, NULL, inputfile, clearfile, FALSE) != 0) {
  1430.         errorLvl = UNKNOWN_FILE_ERROR;
  1431.         user_error();
  1432.         }
  1433.         if (clearfile)
  1434.         rmtemp(clearfile);
  1435.     } else {
  1436.         if (writePhantomOutput(workfile) < 0) {
  1437.         errorLvl = UNKNOWN_FILE_ERROR;
  1438.         user_error();
  1439.         }
  1440.     }
  1441.     rmtemp(workfile);
  1442.     } else {
  1443.     char name[MAX_PATH];
  1444.         char *t;
  1445.     if (outputfile) {
  1446.         strcpy(name, outputfile);
  1447.     } else {
  1448.         strcpy(name, inputfile);
  1449.         drop_extension(name);
  1450.     }
  1451.         do {
  1452.         if (!outputfile && no_extension(name)) {
  1453.             if (emit_radix_64)
  1454.             force_extension(name, ASC_EXTENSION);
  1455.             else if (sign_flag && separate_signature)
  1456.             force_extension(name, SIG_EXTENSION);
  1457.             else
  1458.             force_extension(name, PGP_EXTENSION);
  1459. #ifdef MACTC5
  1460.             if (addresfork) {
  1461.                 drop_extension(name);
  1462.                 force_extension(name, ".sdf");
  1463.             }
  1464. #endif
  1465.         }
  1466.             if (!file_exists(name)) break;
  1467.             t=ck_dup_output(name, TRUE, !clearfile);
  1468.             if (t==NULL) user_error();
  1469.             if (clearfile && !strcmp(t,name)) break;
  1470.             strcpy(name,t);
  1471.         } while (TRUE);
  1472.     if (emit_radix_64) {
  1473.         if (armor_file(workfile, name, inputfile, clearfile, FALSE) != 0) {
  1474.         errorLvl = UNKNOWN_FILE_ERROR;
  1475.         user_error();
  1476.         }
  1477.         if (clearfile)
  1478.         rmtemp(clearfile);
  1479.     } else {
  1480.         if ((outputfile = savetemp(workfile, name)) == NULL) {
  1481.         errorLvl = UNKNOWN_FILE_ERROR;
  1482.         user_error();
  1483.         }
  1484.         if (!quietmode) {
  1485.         if (encrypt_flag)
  1486.             fprintf(pgpout,
  1487.                 LANG("\nCiphertext file: %s\n"), outputfile);
  1488.         else if (sign_flag)
  1489.             fprintf(pgpout,
  1490.                 LANG("\nSignature file: %s\n"), outputfile);
  1491.         }
  1492.     }
  1493. #ifdef MACTC5
  1494.         AddOutputFiles(name);
  1495.         if (addresfork) {
  1496.             if(!AddResourceFork(name)) {
  1497.                 short frefnum,len,i;
  1498.                 char *p,*q;
  1499.                 Handle h;
  1500.                 c2pstr(name);
  1501.                 q=file_tail(argv[2]);
  1502.                 len=strlen(q);
  1503.                 frefnum=OpenResFile((uchar *)name);
  1504.                 h=NewHandle(len+1);
  1505.                 HLock(h);
  1506.                 p=*h;
  1507.                 *p++=len;
  1508.                 for (i=0; i<len; i++) *p++=*q++;
  1509.                 AddResource(h,'STR ',500,(uchar *)"");
  1510.                 ChangedResource(h);
  1511.                 WriteResource(h);
  1512.                 UpdateResFile(frefnum);
  1513.                 CloseResFile(frefnum);
  1514.                 p2cstr((uchar *)name);
  1515.             } else {
  1516.                 BailoutAlert("AddResFork failed!");
  1517.                 exitPGP(-1);
  1518.             }
  1519.         }
  1520.         if (binhex_flag) {
  1521.             if (binhex(name)) {
  1522.                 BailoutAlert("BinHex failed!");
  1523.                 exitPGP(-1);
  1524.             }
  1525.             remove(name);
  1526.         }
  1527.         if (use_clipboard) File2Scrap(name);
  1528. #endif /* MACTC5 */
  1529.     }
  1530.  
  1531.     if (wipeflag) {
  1532.     /* destroy every trace of plaintext */
  1533.     if (wipefile(inputfile) == 0) {
  1534.         remove(inputfile);
  1535.         fprintf(pgpout, LANG("\nFile %s wiped and deleted. "), inputfile);
  1536.         fprintf(pgpout, "\n");
  1537.     }
  1538.     }
  1539.  
  1540. #ifdef MACTC5
  1541.     if(!addresfork && !use_clipboard)
  1542.         if (!emit_radix_64) PGPSetFinfo(outputfile,'Cryp','MPGP');
  1543. #endif
  1544.  
  1545.     exitPGP(EXIT_OK);
  1546.     return 0;            /* to shut up lint and some compilers */
  1547. #ifdef MACTC5
  1548. }                /* pgp_dispatch */
  1549. #else
  1550. }                /* main */
  1551. #endif
  1552.  
  1553. #ifdef MSDOS
  1554. #include <dos.h>
  1555. static char *dos_errlst[] =
  1556. {
  1557.     "Write protect error",    /* LANG ("Write protect error") */
  1558.     "Unknown unit",
  1559.     "Drive not ready",        /* LANG ("Drive not ready") */
  1560.     "3", "4", "5", "6", "7", "8", "9",
  1561.     "Write error",        /* LANG ("Write error") */
  1562.     "Read error",        /* LANG ("Read error") */
  1563.     "General failure",
  1564. };
  1565.  
  1566. /* handler for msdos 'harderrors' */
  1567. #ifndef OS2
  1568. #ifdef __TURBOC__        /* Turbo C 2.0 */
  1569. static int dostrap(int errval)
  1570. #else
  1571. static void dostrap(unsigned deverr, unsigned errval)
  1572. #endif
  1573. {
  1574.     char errbuf[64];
  1575.     int i;
  1576.     sprintf(errbuf, "\r\nDOS error: %s\r\n", dos_errlst[errval]);
  1577.     i = 0;
  1578.     do
  1579.     bdos(2, (unsigned int) errbuf[i], 0);
  1580.     while (errbuf[++i]);
  1581. #ifdef __TURBOC__
  1582.     return 0;            /* ignore (fopen will return NULL) */
  1583. #else
  1584.     return;
  1585. #endif
  1586. }
  1587. #endif                /* MSDOS */
  1588. #endif
  1589.  
  1590. static void initsigs()
  1591. {
  1592. #ifdef MSDOS
  1593. #ifndef OS2
  1594. #ifdef __TURBOC__
  1595.     harderr(dostrap);
  1596. #else                /* MSC */
  1597. #ifndef __GNUC__        /* DJGPP's not MSC */
  1598.     _harderr(dostrap);
  1599. #endif
  1600. #endif
  1601. #endif
  1602. #endif                /* MSDOS */
  1603. #ifdef SIGINT
  1604.     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  1605.     signal(SIGINT, breakHandler);
  1606. #if defined(UNIX) || defined(VMS) || defined(ATARI)
  1607. #ifndef __PUREC__ /* PureC doesn't recognise all signals */
  1608.     if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
  1609.     signal(SIGHUP, breakHandler);
  1610.     if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
  1611.     signal(SIGQUIT, breakHandler);
  1612. #endif
  1613. #ifdef UNIX
  1614.     signal(SIGPIPE, breakHandler);
  1615. #endif
  1616.     signal(SIGTERM, breakHandler);
  1617. #ifdef MACTC5
  1618.     signal(SIGABRT,breakHandler);
  1619.     signal(SIGTERM,breakHandler);
  1620. #ifndef DEBUG
  1621.     signal(SIGTRAP, breakHandler);
  1622.     signal(SIGSEGV, breakHandler);
  1623.     signal(SIGILL, breakHandler);
  1624. #ifdef SIGBUS
  1625.     signal(SIGBUS, breakHandler);
  1626. #endif
  1627. #endif                /* DEBUG */
  1628. #endif                /* MACTC5 */
  1629. #endif                /* UNIX */
  1630. #endif                /* SIGINT */
  1631. }                /* initsigs */
  1632.  
  1633.  
  1634. static void do_armorfile(char *armorfile)
  1635. {
  1636.     char *tempf;
  1637.     char cipherfile[MAX_PATH];
  1638.     long lastpos, linepos = 0;
  1639.     int status;
  1640.     int success = 0;
  1641.  
  1642.     for (;;) {
  1643.     /* Handle transport armor stripping */
  1644.     tempf = tempfile(0);
  1645.     strip_spaces = FALSE;    /* de_armor_file() sets
  1646.                    this for clear signature files */
  1647.         use_charset_header = TRUE;
  1648.         lastpos = linepos;
  1649.     status = de_armor_file(armorfile, tempf, &linepos);
  1650.     if (status) {
  1651.         fprintf(pgpout,
  1652. LANG("\n\007Error: Transport armor stripping failed for file %s\n"),
  1653.             armorfile);
  1654.         errorLvl = INVALID_FILE_ERROR;
  1655.         user_error();    /* Bad file */
  1656.     }
  1657.     if (keepctx || de_armor_only) {
  1658.         if (outputfile && de_armor_only) {
  1659.         if (strcmp(outputfile, "-") == 0) {
  1660.             writePhantomOutput(tempf);
  1661.             rmtemp(tempf);
  1662.             return;
  1663.         }
  1664.         strcpy(cipherfile, outputfile);
  1665.         } else {
  1666.         strcpy(cipherfile, file_tail(armorfile));
  1667.         force_extension(cipherfile, PGP_EXTENSION);
  1668.         }
  1669.         if ((tempf = savetemp(tempf, cipherfile)) == NULL) {
  1670.         errorLvl = UNKNOWN_FILE_ERROR;
  1671.         user_error();
  1672.         }
  1673.         if (!quietmode)
  1674.         fprintf(pgpout,
  1675. LANG("Stripped transport armor from '%s', producing '%s'.\n"),
  1676.             armorfile, tempf);
  1677.         /* -da flag: don't decrypt */
  1678.         if (de_armor_only || do_decrypt(tempf) >= 0)
  1679.         ++success;
  1680.     } else {
  1681.         if (charset_header[0])        /* Check signature with charset from Charset: header */
  1682.         checksig_pass = 1;
  1683.         if (do_decrypt(tempf) >= 0)
  1684.         ++success;
  1685.         rmtemp(tempf);
  1686.         if (charset_header[0]) {
  1687.         if (checksig_pass == 2) { /* Sigcheck failed: try again with local charset */
  1688.             tempf = tempfile(0);
  1689.             use_charset_header = FALSE;
  1690.             linepos = lastpos;
  1691.             de_armor_file(armorfile, tempf, &linepos);
  1692.             if (do_decrypt(tempf) >= 0)
  1693.                 ++success;
  1694.             rmtemp(tempf);
  1695.         }
  1696.         checksig_pass = 0;
  1697.         }
  1698.     }
  1699.  
  1700.     if (!is_armor_file(armorfile, linepos)) {
  1701.         if (!success)    /* print error msg if we didn't
  1702.                    decrypt anything */
  1703.         user_error();
  1704.         return;
  1705.     }
  1706.     fprintf(pgpout,
  1707.         LANG("\nLooking for next packet in '%s'...\n"), armorfile);
  1708.     }
  1709. }                /* do_armorfile */
  1710.  
  1711.  
  1712. static int do_decrypt(char *cipherfile)
  1713. {
  1714.     char *outfile = NULL;
  1715.     int status, i;
  1716.     boolean nested_info = FALSE;
  1717.     char ringfile[MAX_PATH];
  1718.     byte ctb;
  1719.     byte header[8];        /* used to classify file type at the end. */
  1720.     char preserved_name[MAX_PATH];
  1721.     char *newname;
  1722.  
  1723.     /* will be set to the original file name after processing a
  1724.        literal packet */
  1725.     preserved_name[0] = '\0';
  1726.  
  1727.     do {            /* while nested parsable info present */
  1728.     if (nested_info) {
  1729.         rmtemp(cipherfile);    /* never executed on first pass */
  1730.         cipherfile = outfile;
  1731.     }
  1732.     if (get_header_info_from_file(cipherfile, &ctb, 1) < 0) {
  1733.         fprintf(pgpout,
  1734. LANG("\n\007Can't open ciphertext file '%s'\n"), cipherfile);
  1735.         errorLvl = FILE_NOT_FOUND_ERROR;
  1736.         return -1;
  1737.     }
  1738.     if (!is_ctb(ctb))    /* not a real CTB -- complain */
  1739.         break;
  1740.  
  1741.     if (moreflag)
  1742.         outfile = tempfile(TMP_WIPE | TMP_TMPDIR);
  1743.     else
  1744.         outfile = tempfile(TMP_WIPE);
  1745.  
  1746.     /* PKE is Public Key Encryption */
  1747.     if (is_ctb_type(ctb, CTB_PKE_TYPE)) {
  1748.  
  1749.         if (!quietmode)
  1750.         fprintf(pgpout,
  1751. LANG("\nFile is encrypted.  Secret key is required to read it. "));
  1752.  
  1753.         /* Decrypt to scratch file since we may have a LITERAL2 */
  1754.         status = decryptfile(cipherfile, outfile);
  1755.  
  1756.         if (status < 0) {    /* error return */
  1757.         errorLvl = RSA_DECR_ERROR;
  1758.         return -1;
  1759.         }
  1760.         nested_info = (status > 0);
  1761.  
  1762.     } else if (is_ctb_type(ctb, CTB_SKE_TYPE)) {
  1763.  
  1764.         if (decrypt_only_flag) {
  1765.         /* swap file names instead of just copying the file */
  1766.         rmtemp(outfile);
  1767.         outfile = cipherfile;
  1768.         cipherfile = NULL;
  1769.         if (!quietmode)
  1770.             fprintf(pgpout,
  1771. LANG("\nThis file has a signature, which will be left in place.\n"));
  1772.         nested_info = FALSE;
  1773.         break;        /* Do no more */
  1774.         }
  1775.         if (!quietmode && checksig_pass<=1)
  1776.         fprintf(pgpout,
  1777. LANG("\nFile has signature.  Public key is required to check signature.\n"));
  1778.  
  1779.         status = check_signaturefile(cipherfile, outfile,
  1780.                      strip_sig_flag, preserved_name);
  1781.  
  1782.         if (status < 0) {    /* error return */
  1783.         errorLvl = SIGNATURE_CHECK_ERROR;
  1784.         return -1;
  1785.         }
  1786.         nested_info = (status > 0);
  1787.  
  1788.         if (strcmp(preserved_name, "/dev/null") == 0) {
  1789.         rmtemp(outfile);
  1790.         fprintf(pgpout, "\n");
  1791.         return 0;
  1792.         }
  1793.     } else if (is_ctb_type(ctb, CTB_CKE_TYPE)) {
  1794.  
  1795.         /* Conventional Key Encrypted ciphertext. */
  1796.         /* Tell user it's encrypted here, and prompt for
  1797.            password in subroutine. */
  1798.         if (!quietmode)
  1799.         fprintf(pgpout, LANG("\nFile is conventionally encrypted.  "));
  1800.         /* Decrypt to scratch file since it may be a LITERAL2 */
  1801.         status = idea_decryptfile(cipherfile, outfile);
  1802.         if (status < 0) {    /* error return */
  1803.         errorLvl = DECR_ERROR;
  1804.         return -1;    /* error exit status */
  1805.         }
  1806.         nested_info = (status > 0);
  1807.  
  1808.     } else if (is_ctb_type(ctb, CTB_COMPRESSED_TYPE)) {
  1809.  
  1810.         /* Compressed text. */
  1811.         status = decompress_file(cipherfile, outfile);
  1812.         if (status < 0) {    /* error return */
  1813.         errorLvl = DECOMPRESS_ERROR;
  1814.         return -1;
  1815.         }
  1816.         /* Always assume nested information... */
  1817.         nested_info = TRUE;
  1818.  
  1819.     } else if (is_ctb_type(ctb, CTB_LITERAL_TYPE) ||
  1820.            is_ctb_type(ctb, CTB_LITERAL2_TYPE)) { /* Raw plaintext.
  1821.                                  Just copy it.
  1822.                                  No more nesting.
  1823.                                */
  1824.  
  1825.         /* Strip off CTB_LITERAL prefix byte from file: */
  1826.         /* strip_literal may alter plainfile; will set mode */
  1827.         status = strip_literal(cipherfile, outfile,
  1828.                    preserved_name, &literal_mode);
  1829.         if (status < 0) {    /* error return */
  1830.         errorLvl = UNKNOWN_FILE_ERROR;
  1831.         return -1;
  1832.         }
  1833.         nested_info = FALSE;
  1834.     } else if (ctb == CTB_CERT_SECKEY || ctb == CTB_CERT_PUBKEY) {
  1835.  
  1836.         rmtemp(outfile);
  1837.         if (decrypt_only_flag) {
  1838.         /* swap file names instead of just copying the file */
  1839.         outfile = cipherfile;
  1840.         cipherfile = NULL;
  1841.         nested_info = FALSE;    /* No error */
  1842.         break;        /* no further processing */
  1843.         }
  1844.         /* Key ring.  View it. */
  1845.         fprintf(pgpout,
  1846. LANG("\nFile contains key(s).  Contents follow..."));
  1847.         if (view_keyring(NULL, cipherfile, TRUE, FALSE) < 0) {
  1848.         errorLvl = KEYRING_VIEW_ERROR;
  1849.         return -1;
  1850.         }
  1851.         /* filter mode explicit requested with -f */
  1852.         if (filter_mode && !preserve_filename)
  1853.         return 0;    /*    No output file */
  1854.         if (batchmode)
  1855.         return 0;
  1856.         if (ctb == CTB_CERT_SECKEY)
  1857.         strcpy(ringfile, globalSecringName);
  1858.         else
  1859.         strcpy(ringfile, globalPubringName);
  1860.         /*      Ask if it should be put on key ring */
  1861.         fprintf(pgpout,
  1862. LANG("\nDo you want to add this keyfile to keyring '%s' (y/N)? "), ringfile);
  1863.         if (!getyesno('n'))
  1864.         return 0;
  1865.         status = addto_keyring(cipherfile, ringfile);
  1866.         if (status < 0) {
  1867.         fprintf(pgpout, LANG("\007Keyring add error. "));
  1868.         errorLvl = KEYRING_ADD_ERROR;
  1869.         return -1;
  1870.         }
  1871.         return 0;        /*    No output file */
  1872.  
  1873.     } else {        /* Unrecognized CTB */
  1874.         break;
  1875.     }
  1876.  
  1877.     } while (nested_info);
  1878.     /* No more nested parsable information */
  1879.  
  1880.     /* Stopped early due to error */
  1881.     if (nested_info) {
  1882.     fprintf(pgpout,
  1883. "\7\nERROR: Nested data has unexpected format.  CTB=0x%02X\n", ctb);
  1884.     if (outfile)
  1885.         rmtemp(outfile);
  1886.     if (cipherfile)
  1887.         rmtemp(cipherfile);
  1888.     errorLvl = UNKNOWN_FILE_ERROR;
  1889.     return -1;
  1890.     }
  1891.     if (outfile == NULL) {    /* file was not encrypted */
  1892.     if (!filter_mode && !moreflag) {
  1893.         fprintf(pgpout,
  1894. LANG("\007\nError: '%s' is not a ciphertext, signature, or key file.\n"),
  1895.             cipherfile);
  1896.         errorLvl = UNKNOWN_FILE_ERROR;
  1897.         return -1;
  1898.     }
  1899.     outfile = cipherfile;
  1900.     } else {
  1901.     if (cipherfile)
  1902.         rmtemp(cipherfile);
  1903.     }
  1904.  
  1905.     if (moreflag || (strcmp(preserved_name, CONSOLE_FILENAME) == 0)) {
  1906.     /* blort to screen */
  1907.     if (strcmp(preserved_name, CONSOLE_FILENAME) == 0) {
  1908.         fprintf(pgpout,
  1909. LANG("\n\nThis message is marked \"For your eyes only\".  Display now \
  1910. (Y/n)? "));
  1911.         if (batchmode
  1912. #ifdef UNIX
  1913.             || !isatty(fileno(stdout))    /* stdout is redirected! */
  1914. #endif
  1915.             || filter_mode || !getyesno('y')) {
  1916.         /* no -- abort display, and clean up */
  1917.                 fprintf(pgpout, "\n");
  1918.         rmtemp(outfile);
  1919.         return 0;
  1920.         }
  1921.     }
  1922.     if (!quietmode)
  1923.         fprintf(pgpout, LANG("\n\nPlaintext message follows...\n"));
  1924.     else
  1925.         putc('\n', pgpout);
  1926.     fprintf(pgpout, "------------------------------\n");
  1927.     more_file(outfile, strcmp(preserved_name, CONSOLE_FILENAME) == 0);
  1928.     /* Disallow saving to disk if outfile is console-only: */
  1929.     if (strcmp(preserved_name, CONSOLE_FILENAME) == 0) {
  1930.         clearscreen();    /* remove all evidence */
  1931.     } else if (!quietmode && !batchmode) {
  1932.         fprintf(pgpout, LANG("Save this file permanently (y/N)? "));
  1933.         if (getyesno('n')) {
  1934.         char moreFilename[256];
  1935.         fprintf(pgpout, LANG("Enter filename to save file as: "));
  1936. #ifdef AMIGA
  1937.                 requesterdesc=LANG("Enter filename to save file as: ");
  1938. #endif
  1939.                 if (preserved_name[0]) {
  1940.             fprintf(pgpout, "[%s]: ", file_tail(preserved_name));
  1941. #ifdef AMIGA
  1942.                     strcat(requesterdesc, "[");
  1943.                     strcat(requesterdesc, file_tail(preserved_name));
  1944.                     strcat(requesterdesc, "]:");
  1945. #endif
  1946.                 }
  1947. #ifdef MACTC5
  1948.         if(!GetFilePath(LANG("Enter filename to save file as:"),moreFilename,PUTFILE))
  1949.             strcpy(moreFilename,"");
  1950.         else
  1951.             fprintf(pgpout, "%s\n",moreFilename);
  1952. #else
  1953.         getstring(moreFilename, 255, TRUE);
  1954. #endif
  1955.         if (*moreFilename == '\0') {
  1956.             if (*preserved_name != '\0')
  1957.             savetemp(outfile, file_tail(preserved_name));
  1958.             else
  1959.             rmtemp(outfile);
  1960.         } else
  1961.             savetemp(outfile, moreFilename);
  1962.         return 0;
  1963.         }
  1964.     }
  1965.     rmtemp(outfile);
  1966.     return 0;
  1967.     }                /* blort to screen */
  1968.     if (outputfile) {
  1969.     if (!strcmp(outputfile, "/dev/null")) {
  1970.         rmtemp(outfile);
  1971.         return 0;
  1972.     }
  1973.     filter_mode = (strcmp(outputfile, "-") == 0);
  1974.     strcpy(plainfile, outputfile);
  1975.     } else {
  1976. #ifdef VMS
  1977.     /* VMS null extension has to be ".", not "" */
  1978.     force_extension(plainfile, ".");
  1979. #else                /* not VMS */
  1980.     drop_extension(plainfile);
  1981. #endif                /* not VMS */
  1982.     }
  1983.  
  1984.     if (!preserve_filename && filter_mode) {
  1985.     if (writePhantomOutput(outfile) < 0) {
  1986.         errorLvl = UNKNOWN_FILE_ERROR;
  1987.         return -1;
  1988.     }
  1989.     rmtemp(outfile);
  1990.     return 0;
  1991.     }
  1992.     if (preserve_filename && preserved_name[0] != '\0')
  1993.     strcpy(plainfile, file_tail(preserved_name));
  1994.  
  1995.     if (quietmode) {
  1996.     if (savetemp(outfile, plainfile) == NULL) {
  1997.         errorLvl = UNKNOWN_FILE_ERROR;
  1998.         return -1;
  1999.     }
  2000.     return 0;
  2001.     }
  2002.     if (!verbose)           /* if other filename messages were suppressed */
  2003.     fprintf(pgpout, LANG("\nPlaintext filename: %s"), plainfile);
  2004.  
  2005.  
  2006. /*---------------------------------------------------------*/
  2007.  
  2008.     /*      One last thing-- let's attempt to classify some of the more
  2009.        frequently occurring cases of plaintext output files, as an
  2010.        aid to the user.
  2011.  
  2012.        For example, if output file is a public key, it should have
  2013.        the right extension on the filename.
  2014.  
  2015.        Also, it will likely be common to encrypt files created by
  2016.        various archivers, so they should be renamed with the archiver
  2017.        extension.
  2018.      */
  2019.     get_header_info_from_file(outfile, header, 8);
  2020.  
  2021.     newname = NULL;
  2022. #ifdef MACTC5
  2023.     if (header[0] == CTB_CERT_SECKEY)
  2024.         PGPSetFinfo(plainfile,'SKey','MPGP');
  2025. #endif
  2026.     if (header[0] == CTB_CERT_PUBKEY) {
  2027.     /* Special case--may be public key, worth renaming */
  2028. #ifdef MACTC5
  2029.         PGPSetFinfo(plainfile,'PKey','MPGP');
  2030. #endif
  2031.     fprintf(pgpout,
  2032. LANG("\nPlaintext file '%s' looks like it contains a public key."),
  2033.         plainfile);
  2034.     newname = maybe_force_extension(plainfile, PGP_EXTENSION);
  2035.     }
  2036.     /* Possible public key output file */
  2037.     else if ((i = compressSignature(header)) >= 0) {
  2038.     /*      Special case--may be an archived/compressed file,
  2039.         worth renaming
  2040.     */
  2041.     fprintf(pgpout, LANG("\nPlaintext file '%s' looks like a %s file."),
  2042.         plainfile, compressName[i]);
  2043.     newname = maybe_force_extension(plainfile, compressExt[i]);
  2044.     } else if (is_ctb(header[0]) &&
  2045.            (is_ctb_type(header[0], CTB_PKE_TYPE)
  2046.         || is_ctb_type(header[0], CTB_SKE_TYPE)
  2047.         || is_ctb_type(header[0], CTB_CKE_TYPE))) {
  2048.     /* Special case--may be another ciphertext file, worth renaming */
  2049.     fprintf(pgpout,
  2050. LANG("\n\007Output file '%s' may contain more ciphertext or signature."),
  2051.         plainfile);
  2052.     newname = maybe_force_extension(plainfile, PGP_EXTENSION);
  2053.     }                /* Possible ciphertext output file */
  2054. #ifdef MACTC5
  2055.     if( (newname = savetemp(outfile, (newname ? newname : plainfile))) == NULL) {
  2056. #else
  2057.     if (savetemp(outfile, (newname ? newname : plainfile)) == NULL) {
  2058. #endif
  2059.     errorLvl = UNKNOWN_FILE_ERROR;
  2060.     return -1;
  2061.     }
  2062. #ifdef MACTC5
  2063.     else if( strcmp(newname, plainfile) != 0 )    /* 203a */
  2064.         strcpy(plainfile, newname);
  2065. #endif
  2066.     fprintf(pgpout, "\n");
  2067.     return 0;
  2068. }                /* do_decrypt */
  2069.  
  2070. static int do_keyopt(char keychar)
  2071. {
  2072.     char keyfile[MAX_PATH];
  2073.     char ringfile[MAX_PATH];
  2074.     char *workfile;
  2075.     int status;
  2076.  
  2077.     if ((filter_mode || batchmode)
  2078.     && (keychar == 'g' || keychar == 'e' || keychar == 'd'
  2079.         || (keychar == 'r' && sign_flag))) {
  2080.     errorLvl = NO_BATCH;
  2081.     arg_error();        /* interactive process, no go in batch mode */
  2082.     }
  2083.     /*
  2084.      * If we're not doing anything that uses stdout, produce output there,
  2085.      * in case user wants to redirect it.
  2086.      */
  2087.     if (!filter_mode)
  2088.     pgpout = stdout;
  2089.  
  2090.     switch (keychar) {
  2091.  
  2092. /*-------------------------------------------------------*/
  2093.     case 'g':
  2094.     {        /*      Key generation
  2095.                Arguments: bitcount, bitcount
  2096.              */
  2097.         char keybits[6], ebits[6], *username = NULL;
  2098.  
  2099.         /*
  2100.          * Why all this code?
  2101.          *
  2102.          * Some people may object to PGP insisting on finding the
  2103.          * manual somewhere in the neighborhood to generate a key.
  2104.          * They bristle against this seemingly authoritarian
  2105.          * attitude.  Some people have even modified PGP to defeat
  2106.          * this feature, and redistributed their hotwired version to
  2107.          * others.  That creates problems for me (PRZ).
  2108.          *
  2109.          * Here is the problem.  Before I added this feature, there
  2110.          * were maimed versions of the PGP distribution package
  2111.          * floating around that lacked the manual.  One of them was
  2112.          * uploaded to Compuserve, and was distributed to countless
  2113.          * users who called me on the phone to ask me why such a
  2114.          * complicated program had no manual.  It spread out to BBS
  2115.          * systems around the country.  And a freeware distributor got
  2116.          * hold of the package from Compuserve and enshrined it on
  2117.          * CD-ROM, distributing thousands of copies without the
  2118.          * manual.  What a mess.
  2119.          *
  2120.          * Please don't make my life harder by modifying PGP to
  2121.          * disable this feature so that others may redistribute PGP
  2122.          * without the manual.  If you run PGP on a palmtop with no
  2123.          * memory for the manual, is it too much to ask that you type
  2124.          * one little extra word on the command line to do a key
  2125.          * generation, a command that is seldom used by people who
  2126.          * already know how to use PGP?  If you can't stand even this
  2127.          * trivial inconvenience, can you suggest a better method of
  2128.          * reducing PGP's distribution without the manual?
  2129.          *
  2130.          * PLEASE DO NOT DISABLE THIS CHECK IN THE SOURCE CODE
  2131.          * WITHOUT AT LEAST CALLING PHILIP ZIMMERMANN
  2132.          * (+1 303 541-0140, or prz@acm.org) TO DISCUSS IT.
  2133.          */
  2134.         if (!nomanual && manuals_missing()) {
  2135.         char const *const *dir;
  2136.         fputs(LANG("\a\nError: PGP User's Guide not found.\n\
  2137. PGP looked for it in the following directories:\n"), pgpout);
  2138. #ifdef MACTC5
  2139.         fprintf(pgpout, "\t\"%s\"\n", appPathName);
  2140. #else
  2141.         for (dir = manual_dirs; *dir; dir++)
  2142.             fprintf(pgpout, "\t\"%s\"\n", *dir);
  2143. #endif    /* MACTC5 */
  2144.         fputs(
  2145. LANG("and the doc subdirectory of each of the above.  Please put a copy of\n\
  2146. both volumes of the User's Guide in one of these directories.\n\
  2147. \n\
  2148. Under NO CIRCUMSTANCES should PGP ever be distributed without the PGP\n\
  2149. User's Guide, which is included in the standard distribution package.\n\
  2150. If you got a copy of PGP without the manual, please inform whomever you\n\
  2151. got it from that this is an incomplete package that should not be\n\
  2152. distributed further.\n\
  2153. \n\
  2154. PGP will not generate a key without finding the User's Guide.\n\
  2155. There is a simple way to override this restriction.  See the\n\
  2156. PGP User's Guide for details on how to do it.\n\
  2157. \n"), pgpout);
  2158.         return KEYGEN_ERROR;
  2159.         }
  2160.         if (myArgc > 2)
  2161.         strncpy(keybits, myArgv[2], sizeof(keybits) - 1);
  2162.         else
  2163.         keybits[0] = '\0';
  2164.  
  2165.         if (myArgc > 3)
  2166.         strncpy(ebits, myArgv[3], sizeof(ebits) - 1);
  2167.         else
  2168.         ebits[0] = '\0';
  2169.  
  2170.         /* If the -u option is given, use that username */
  2171.         if (u_flag && my_name != NULL && *my_name != '\0')
  2172.         username = my_name;
  2173.  
  2174.         /* dokeygen writes the keys out to the key rings... */
  2175.         status = dokeygen(keybits, ebits, username);
  2176.  
  2177.         if (status < 0) {
  2178.         fprintf(pgpout, LANG("\007Keygen error. "));
  2179.         errorLvl = KEYGEN_ERROR;
  2180.         }
  2181. #ifdef MACTC5
  2182.         else  {
  2183.             strcpy(ringfile, globalPubringName );
  2184.             PGPSetFinfo(ringfile,'PKey','MPGP');
  2185.             strcpy(ringfile, globalSecringName  );
  2186.             PGPSetFinfo(ringfile,'SKey','MPGP');
  2187.         }
  2188. #endif
  2189.         return status;
  2190.     }            /* Key generation */
  2191.  
  2192. /*-------------------------------------------------------*/
  2193.     case 'c':
  2194.     {            /*      Key checking
  2195.                    Arguments: userid, ringfile
  2196.                  */
  2197.  
  2198.         if (myArgc < 3) {    /* Default to all user ID's */
  2199.         mcguffin[0] = '\0';
  2200.         } else {
  2201.         strcpy(mcguffin, myArgv[2]);
  2202.         if (strcmp(mcguffin, "*") == 0)
  2203.             mcguffin[0] = '\0';
  2204.         }
  2205.         CONVERT_TO_CANONICAL_CHARSET(mcguffin);
  2206.  
  2207.         if (myArgc < 4)    /* default key ring filename */
  2208.         strcpy(ringfile, globalPubringName);
  2209.         else
  2210.         strncpy(ringfile, myArgv[3], sizeof(ringfile) - 1);
  2211.  
  2212.         if ((myArgc < 4 && myArgc > 2)     /* Allow just key file as arg */
  2213.         &&has_extension(myArgv[2], PGP_EXTENSION)) {
  2214.         strcpy(ringfile, myArgv[2]);
  2215.         mcguffin[0] = '\0';
  2216.         }
  2217.         status = dokeycheck(mcguffin, ringfile, CHECK_ALL);
  2218.  
  2219.         if (status < 0) {
  2220.         fprintf(pgpout, LANG("\007Keyring check error.\n"));
  2221.         errorLvl = KEYRING_CHECK_ERROR;
  2222.         }
  2223.         if (status >= 0 && mcguffin[0] != '\0')
  2224.         return status;    /* just checking a single user,
  2225.                    dont do maintenance */
  2226.  
  2227.         if ((status = maint_check(ringfile, 0)) < 0 && status != -7) {
  2228.         fprintf(pgpout, LANG("\007Maintenance pass error. "));
  2229.         errorLvl = KEYRING_CHECK_ERROR;
  2230.         }
  2231. #ifdef MACTC5
  2232.         {
  2233.         byte ctb;
  2234.         get_header_info_from_file(ringfile, &ctb, 1);
  2235.         if (ctb == CTB_CERT_SECKEY)
  2236.             PGPSetFinfo(ringfile,'SKey','MPGP');
  2237.         else if (ctb == CTB_CERT_PUBKEY)
  2238.         PGPSetFinfo(ringfile,'PKey','MPGP');
  2239.         }
  2240. #endif
  2241.         return status == -7 ? 0 : status;
  2242.     }            /* Key check */
  2243.  
  2244. /*-------------------------------------------------------*/
  2245.     case 'm':
  2246.     {            /*      Maintenance pass
  2247.                    Arguments: ringfile
  2248.                  */
  2249.  
  2250.         if (myArgc < 3)    /* default key ring filename */
  2251.         strcpy(ringfile, globalPubringName);
  2252.         else
  2253.         strcpy(ringfile, myArgv[2]);
  2254.  
  2255. #ifdef MSDOS
  2256.         strlwr(ringfile);
  2257. #endif
  2258.         if (!file_exists(ringfile))
  2259.         default_extension(ringfile, PGP_EXTENSION);
  2260.  
  2261.         if ((status = maint_check(ringfile,
  2262.               MAINT_VERBOSE | (c_flag ? MAINT_CHECK : 0))) < 0) {
  2263.         if (status == -7)
  2264.             fprintf(pgpout,
  2265.                 LANG("File '%s' is not a public keyring\n"),
  2266.                 ringfile);
  2267.         fprintf(pgpout, LANG("\007Maintenance pass error. "));
  2268.         errorLvl = KEYRING_CHECK_ERROR;
  2269.         }
  2270. #ifdef MACTC5
  2271.         PGPSetFinfo(ringfile,'PKey','MPGP');
  2272. #endif
  2273.         return status;
  2274.     }            /* Maintenance pass */
  2275.  
  2276. /*-------------------------------------------------------*/
  2277.     case 's':
  2278.     {            /*      Key signing
  2279.                    Arguments: her_id, keyfile
  2280.                  */
  2281.  
  2282.         if (myArgc >= 4)
  2283.         strncpy(keyfile, myArgv[3], sizeof(keyfile) - 1);
  2284.         else
  2285.         strcpy(keyfile, globalPubringName);
  2286.  
  2287.         if (myArgc >= 3) {
  2288.         strcpy(mcguffin, myArgv[2]);    /* Userid to sign */
  2289.         } else {
  2290.         fprintf(pgpout,
  2291. LANG("\nA user ID is required to select the public key you want to sign. "));
  2292.         if (batchmode)    /* not interactive, userid
  2293.                    must be on command line */
  2294.             return -1;
  2295.         fprintf(pgpout, LANG("\nEnter the public key's user ID: "));
  2296. #ifdef AMIGA
  2297.                 requesterdesc=LANG("\nEnter the public key's user ID: ");
  2298. #endif
  2299.         getstring(mcguffin, 255, TRUE);        /* echo keyboard */
  2300.         }
  2301.         CONVERT_TO_CANONICAL_CHARSET(mcguffin);
  2302.  
  2303.         if (my_name[0] == '\0') {
  2304.         fprintf(pgpout,
  2305. LANG("\nA secret key is required to make a signature. "));
  2306.         fprintf(pgpout,
  2307. LANG("\nYou specified no user ID to select your secret key,\n\
  2308. so the default user ID and key will be the most recently\n\
  2309. added key on your secret keyring.\n"));
  2310.         }
  2311.         status = signkey(mcguffin, my_name, keyfile);
  2312.  
  2313.         if (status >= 0) {
  2314.         status = maint_update(keyfile, 0);
  2315.         if (status == -7) { /* ringfile is a keyfile or
  2316.                        secret keyring */
  2317.             fprintf(pgpout,
  2318.                 "Warning: '%s' is not a public keyring\n",
  2319.                 keyfile);
  2320.             return 0;
  2321.         }
  2322.         if (status < 0)
  2323.             fprintf(pgpout, LANG("\007Maintenance pass error. "));
  2324.         }
  2325.         if (status < 0) {
  2326.         fprintf(pgpout, LANG("\007Key signature error. "));
  2327.         errorLvl = KEY_SIGNATURE_ERROR;
  2328.         }
  2329. #ifdef MACTC5
  2330.         PGPSetFinfo(keyfile,'PKey','MPGP');
  2331. #endif
  2332.         return status;
  2333.     }            /* Key signing */
  2334.  
  2335.  
  2336. /*-------------------------------------------------------*/
  2337.     case 'd':
  2338.     {            /*      disable/revoke key
  2339.                    Arguments: userid, keyfile
  2340.                  */
  2341.  
  2342.         if (myArgc >= 4)
  2343.         strncpy(keyfile, myArgv[3], sizeof(keyfile) - 1);
  2344.         else
  2345.         strcpy(keyfile, globalPubringName);
  2346.  
  2347.         if (myArgc >= 3) {
  2348.         strcpy(mcguffin, myArgv[2]);    /* Userid to sign */
  2349.         } else {
  2350.         fprintf(pgpout,
  2351. LANG("\nA user ID is required to select the key you want to revoke or \
  2352. disable. "));
  2353.         fprintf(pgpout, LANG("\nEnter user ID: "));
  2354. #ifdef AMIGA
  2355.                 requesterdesc=LANG("\nEnter user ID: ");
  2356. #endif
  2357.         getstring(mcguffin, 255, TRUE);        /* echo keyboard */
  2358.         }
  2359.         CONVERT_TO_CANONICAL_CHARSET(mcguffin);
  2360.  
  2361.         status = disable_key(mcguffin, keyfile);
  2362.  
  2363.         if (status >= 0) {
  2364.         status = maint_update(keyfile, 0);
  2365.         if (status == -7) { /* ringfile is a keyfile or
  2366.                        secret keyring */
  2367.             fprintf(pgpout, "Warning: '%s' is not a public keyring\n",
  2368.                 keyfile);
  2369.             return 0;
  2370.         }
  2371.         if (status < 0)
  2372.             fprintf(pgpout, LANG("\007Maintenance pass error. "));
  2373.         }
  2374.         if (status < 0)
  2375.         errorLvl = KEY_SIGNATURE_ERROR;
  2376. #ifdef MACTC5
  2377.         PGPSetFinfo(keyfile,'PKey','MPGP');
  2378. #endif
  2379.         return status;
  2380.     }            /* Key compromise */
  2381.  
  2382. /*-------------------------------------------------------*/
  2383.     case 'e':
  2384.     {            /*      Key editing
  2385.                    Arguments: userid, ringfile
  2386.                  */
  2387.  
  2388.         if (myArgc >= 4)
  2389.         strncpy(ringfile, myArgv[3], sizeof(ringfile) - 1);
  2390.         else        /* default key ring filename */
  2391.         strcpy(ringfile, globalPubringName);
  2392.  
  2393.         if (myArgc >= 3) {
  2394.         strcpy(mcguffin, myArgv[2]);    /* Userid to edit */
  2395.         } else {
  2396.         fprintf(pgpout,
  2397. LANG("\nA user ID is required to select the key you want to edit. "));
  2398.         fprintf(pgpout, LANG("\nEnter the key's user ID: "));
  2399. #ifdef AMIGA
  2400.                 requesterdesc=LANG("\nEnter the key's user ID: ");
  2401. #endif
  2402.         getstring(mcguffin, 255, TRUE);        /* echo keyboard */
  2403.         }
  2404.         CONVERT_TO_CANONICAL_CHARSET(mcguffin);
  2405.  
  2406.         status = dokeyedit(mcguffin, ringfile);
  2407.  
  2408.         if (status >= 0) {
  2409.         status = maint_update(ringfile, 0);
  2410.         if (status == -7)
  2411.             status = 0;    /* ignore "not a public keyring" error */
  2412.         if (status < 0)
  2413.             fprintf(pgpout, LANG("\007Maintenance pass error. "));
  2414.         }
  2415.         if (status < 0) {
  2416.         fprintf(pgpout, LANG("\007Keyring edit error. "));
  2417.         errorLvl = KEYRING_EDIT_ERROR;
  2418.         }
  2419. #ifdef MACTC5
  2420.         {
  2421.         byte ctb;
  2422.         get_header_info_from_file(ringfile, &ctb, 1);
  2423.         if (ctb == CTB_CERT_SECKEY)
  2424.             PGPSetFinfo(ringfile,'SKey','MPGP');
  2425.         else if (ctb == CTB_CERT_PUBKEY)
  2426.         PGPSetFinfo(ringfile,'PKey','MPGP');
  2427.         }
  2428. #endif
  2429.         return status;
  2430.     }            /* Key edit */
  2431.  
  2432. /*-------------------------------------------------------*/
  2433.     case 'a':
  2434.     {            /*      Add key to key ring
  2435.                    Arguments: keyfile, ringfile
  2436.                  */
  2437.  
  2438.         if (myArgc < 3 && !filter_mode)
  2439.         arg_error();
  2440.  
  2441.         if (!filter_mode) {    /* Get the keyfile from args */
  2442.         strncpy(keyfile, myArgv[2], sizeof(keyfile) - 1);
  2443.  
  2444. #ifdef MSDOS
  2445.         strlwr(keyfile);
  2446. #endif
  2447.         if (!file_exists(keyfile))
  2448.             default_extension(keyfile, PGP_EXTENSION);
  2449.  
  2450.         if (!file_exists(keyfile)) {
  2451.             fprintf(pgpout,
  2452.                 LANG("\n\007Key file '%s' does not exist.\n"),
  2453.                 keyfile);
  2454.             errorLvl = NONEXIST_KEY_ERROR;
  2455.             return -1;
  2456.         }
  2457.         workfile = keyfile;
  2458.  
  2459.         } else {
  2460.         workfile = tempfile(TMP_WIPE | TMP_TMPDIR);
  2461.         readPhantomInput(workfile);
  2462.         }
  2463.  
  2464.         if (myArgc < (filter_mode ? 3 : 4)) { /* default key ring
  2465.                              filename */
  2466.         byte ctb;
  2467.         get_header_info_from_file(workfile, &ctb, 1);
  2468.         if (ctb == CTB_CERT_SECKEY)
  2469.             strcpy(ringfile, globalSecringName);
  2470.         else
  2471.             strcpy(ringfile, globalPubringName);
  2472.         } else {
  2473.         strncpy(ringfile, myArgv[(filter_mode ? 2 : 3)],
  2474.             sizeof(ringfile) - 1);
  2475.         default_extension(ringfile, PGP_EXTENSION);
  2476.         }
  2477. #ifdef MSDOS
  2478.         strlwr(ringfile);
  2479. #endif
  2480.  
  2481.         status = addto_keyring(workfile, ringfile);
  2482.  
  2483.         if (filter_mode)
  2484.         rmtemp(workfile);
  2485.  
  2486.         if (status < 0) {
  2487.         fprintf(pgpout, LANG("\007Keyring add error. "));
  2488.         errorLvl = KEYRING_ADD_ERROR;
  2489.         }
  2490. #ifdef MACTC5
  2491.         {
  2492.         byte ctb;
  2493.         get_header_info_from_file(ringfile, &ctb, 1);
  2494.         if (ctb == CTB_CERT_SECKEY)
  2495.             PGPSetFinfo(ringfile,'SKey','MPGP');
  2496.         else if (ctb == CTB_CERT_PUBKEY)
  2497.         PGPSetFinfo(ringfile,'PKey','MPGP');
  2498.         }
  2499. #endif
  2500.         return status;
  2501.     }            /* Add key to key ring */
  2502.  
  2503. /*-------------------------------------------------------*/
  2504.     case 'x':
  2505.     {            /*      Extract key from key ring
  2506.                    Arguments: mcguffin, keyfile, ringfile
  2507.                  */
  2508.  
  2509.         if (myArgc >= (filter_mode ? 4 : 5)) /* default key ring
  2510.                             filename */
  2511.         strncpy(ringfile, myArgv[(filter_mode ? 3 : 4)],
  2512.             sizeof(ringfile) - 1);
  2513.         else
  2514.         strcpy(ringfile, globalPubringName);
  2515.  
  2516.         if (myArgc >= (filter_mode ? 2 : 3)) {
  2517.         if (myArgv[2])
  2518.             /* Userid to extract */
  2519.             strcpy(mcguffin, myArgv[2]);
  2520.         else
  2521.             strcpy(mcguffin, "");
  2522.         } else {
  2523.         fprintf(pgpout,
  2524. LANG("\nA user ID is required to select the key you want to extract. "));
  2525.         if (batchmode)    /* not interactive, userid
  2526.                    must be on command line */
  2527.             return -1;
  2528.         fprintf(pgpout, LANG("\nEnter the key's user ID: "));
  2529. #ifdef AMIGA
  2530.                 requesterdesc=LANG("\nEnter the key's user ID: ");
  2531. #endif
  2532.         getstring(mcguffin, 255, TRUE);        /* echo keyboard */
  2533.         }
  2534.         CONVERT_TO_CANONICAL_CHARSET(mcguffin);
  2535.  
  2536.         if (!filter_mode) {
  2537.         if (myArgc >= 4)
  2538.             strncpy(keyfile, myArgv[3], sizeof(keyfile) - 1);
  2539.         else
  2540.             keyfile[0] = '\0';
  2541.  
  2542.         workfile = keyfile;
  2543.         } else {
  2544.         workfile = tempfile(TMP_WIPE | TMP_TMPDIR);
  2545.         }
  2546.  
  2547. #ifdef MSDOS
  2548.         strlwr(workfile);
  2549.         strlwr(ringfile);
  2550. #endif
  2551.  
  2552.         default_extension(ringfile, PGP_EXTENSION);
  2553.  
  2554.         status = extract_from_keyring(mcguffin, workfile,
  2555.                       ringfile, (filter_mode ? FALSE :
  2556.                              emit_radix_64));
  2557.  
  2558.         if (status < 0) {
  2559.         fprintf(pgpout, LANG("\007Keyring extract error. "));
  2560.         errorLvl = KEYRING_EXTRACT_ERROR;
  2561.         if (filter_mode)
  2562.             rmtemp(workfile);
  2563.         return status;
  2564.         }
  2565.         if (filter_mode && !status) {
  2566.         if (emit_radix_64) {
  2567.             /* NULL for outputfile means write to stdout */
  2568.             if (armor_file(workfile, NULL, NULL, NULL, FALSE) != 0) {
  2569.             errorLvl = UNKNOWN_FILE_ERROR;
  2570.             return -1;
  2571.             }
  2572.         } else {
  2573.             if (writePhantomOutput(workfile) < 0) {
  2574.             errorLvl = UNKNOWN_FILE_ERROR;
  2575.             return -1;
  2576.             }
  2577.         }
  2578.         rmtemp(workfile);
  2579.         }
  2580. #ifdef MACTC5
  2581.         if (status)
  2582.             return KEYRING_EXTRACT_ERROR;
  2583.         if ((!emit_radix_64)&&(strlen(keyfile)>0)) {
  2584.         byte ctb;
  2585.         get_header_info_from_file(keyfile, &ctb, 1);
  2586.         if (ctb == CTB_CERT_SECKEY)
  2587.             PGPSetFinfo(ringfile,'SKey','MPGP');
  2588.         else if (ctb == CTB_CERT_PUBKEY)
  2589.             PGPSetFinfo(ringfile,'PKey','MPGP');
  2590.         }
  2591. #endif
  2592.         return 0;
  2593.     }            /* Extract key from key ring */
  2594.  
  2595. /*-------------------------------------------------------*/
  2596.     case 'r':
  2597.     {    /*      Remove keys or selected key signatures from userid keys
  2598.             Arguments: userid, ringfile
  2599.          */
  2600.  
  2601.         if (myArgc >= 4)
  2602.         strcpy(ringfile, myArgv[3]);
  2603.         else        /* default key ring filename */
  2604.         strcpy(ringfile, globalPubringName);
  2605.  
  2606.         if (myArgc >= 3) {
  2607.         strcpy(mcguffin, myArgv[2]);    /* Userid to work on */
  2608.         } else {
  2609.         if (sign_flag) {
  2610.             fprintf(pgpout,
  2611. LANG("\nA user ID is required to select the public key you want to\n\
  2612. remove certifying signatures from. "));
  2613.         } else {
  2614.             fprintf(pgpout,
  2615. LANG("\nA user ID is required to select the key you want to remove. "));
  2616.         }
  2617.         if (batchmode)    /* not interactive, userid must be on
  2618.                    command line */
  2619.             return -1;
  2620.         fprintf(pgpout, LANG("\nEnter the key's user ID: "));
  2621. #ifdef AMIGA
  2622.                 requesterdesc=LANG("\nEnter the key's user ID: ");
  2623. #endif
  2624.         getstring(mcguffin, 255, TRUE);        /* echo keyboard */
  2625.         }
  2626.         CONVERT_TO_CANONICAL_CHARSET(mcguffin);
  2627.  
  2628. #ifdef MSDOS
  2629.         strlwr(ringfile);
  2630. #endif
  2631.         if (!file_exists(ringfile))
  2632.         default_extension(ringfile, PGP_EXTENSION);
  2633.  
  2634.         if (sign_flag) {    /* Remove signatures */
  2635.         if (remove_sigs(mcguffin, ringfile) < 0) {
  2636.             fprintf(pgpout, LANG("\007Key signature remove error. "));
  2637.             errorLvl = KEYSIG_REMOVE_ERROR;
  2638.             return -1;
  2639.         }
  2640.         } else {        /* Remove keyring */
  2641. #ifdef MACTC5
  2642.             if (remove_from_keyring( NULL, mcguffin, ringfile,
  2643.                     (boolean)!strcmp(ringfile, globalPubringName))) {
  2644. #else
  2645.         if (remove_from_keyring(NULL, mcguffin, ringfile,
  2646.                     (boolean) (myArgc < 4)) < 0) {
  2647. #endif
  2648.             fprintf(pgpout, LANG("\007Keyring remove error. "));
  2649.             errorLvl = KEYRING_REMOVE_ERROR;
  2650.             return -1;
  2651.         }
  2652.         }
  2653. #ifdef MACTC5
  2654.         {
  2655.         byte ctb;
  2656.         get_header_info_from_file(ringfile, &ctb, 1);
  2657.         if (ctb == CTB_CERT_SECKEY)
  2658.             PGPSetFinfo(ringfile,'SKey','MPGP');
  2659.         else if (ctb == CTB_CERT_PUBKEY)
  2660.         PGPSetFinfo(ringfile,'PKey','MPGP');
  2661.         PGPSetFinfo(globalPubringName,'PKey','MPGP');
  2662.         }
  2663. #endif
  2664.         return 0;
  2665.     }            /* remove key signatures from userid */
  2666.  
  2667. /*-------------------------------------------------------*/
  2668.     case 'v':
  2669.     case 'V':            /* -kvv */
  2670.     {            /* View or remove key ring entries,
  2671.                    with userid match
  2672.                    Arguments: userid, ringfile
  2673.                  */
  2674.  
  2675.         if (myArgc < 4)    /* default key ring filename */
  2676.         strcpy(ringfile, globalPubringName);
  2677.         else
  2678.         strcpy(ringfile, myArgv[3]);
  2679.  
  2680.         if (myArgc > 2) {
  2681.         strcpy(mcguffin, myArgv[2]);
  2682.         if (strcmp(mcguffin, "*") == 0)
  2683.             mcguffin[0] = '\0';
  2684.         } else {
  2685.         *mcguffin = '\0';
  2686.         }
  2687.  
  2688.         if ((myArgc == 3) && has_extension(myArgv[2], PGP_EXTENSION)) {
  2689.         strcpy(ringfile, myArgv[2]);
  2690.         mcguffin[0] = '\0';
  2691.         }
  2692.         CONVERT_TO_CANONICAL_CHARSET(mcguffin);
  2693.  
  2694. #ifdef MSDOS
  2695.         strlwr(ringfile);
  2696. #endif
  2697.         if (!file_exists(ringfile))
  2698.         default_extension(ringfile, PGP_EXTENSION);
  2699.  
  2700.         /* If a second 'v' (keychar = V), show signatures too */
  2701.         status = view_keyring(mcguffin, ringfile,
  2702.                   (boolean) (keychar == 'V'), c_flag);
  2703.         if (status < 0) {
  2704.         fprintf(pgpout, LANG("\007Keyring view error. "));
  2705.         errorLvl = KEYRING_VIEW_ERROR;
  2706.         }
  2707. #ifdef MACTC5
  2708.         {
  2709.         byte ctb;
  2710.         get_header_info_from_file(ringfile, &ctb, 1);
  2711.         if (ctb == CTB_CERT_SECKEY)
  2712.             PGPSetFinfo(ringfile,'SKey','MPGP');
  2713.         else if (ctb == CTB_CERT_PUBKEY)
  2714.         PGPSetFinfo(ringfile,'PKey','MPGP');
  2715.         }
  2716. #endif
  2717.         return status;
  2718.     }            /* view key ring entries, with userid match */
  2719.  
  2720.     default:
  2721.     arg_error();
  2722.     }
  2723.     return 0;
  2724. }                /* do_keyopt */
  2725.  
  2726. /* comes here if user made a boo-boo. */
  2727. void user_error()
  2728. {
  2729.     fprintf(pgpout, LANG("\nFor a usage summary, type:  pgp -h\n"));
  2730.     fprintf(pgpout,
  2731.         LANG("For more detailed help, consult the PGP User's Guide.\n"));
  2732.     exitPGP(errorLvl ? errorLvl : 127);        /* error exit */
  2733. }
  2734.  
  2735. #if defined(DEBUG) && defined(linux)
  2736. #include <malloc.h>
  2737. #endif
  2738.  
  2739. /*
  2740.  * exitPGP: wipes and removes temporary files, also tries to wipe
  2741.  * the stack.
  2742.  */
  2743. void exitPGP(int returnval)
  2744. {
  2745.     char buf[STACK_WIPE];
  2746.     struct hashedpw *hpw;
  2747.  
  2748.     if (verbose)
  2749.     fprintf(pgpout, "exitPGP: exitcode = %d\n", returnval);
  2750.     for (hpw = passwds; hpw; hpw = hpw->next)
  2751.     memset(hpw->hash, 0, sizeof(hpw->hash));
  2752.     for (hpw = keypasswds; hpw; hpw = hpw->next)
  2753.     memset(hpw->hash, 0, sizeof(hpw->hash));
  2754. #ifdef MACTC5
  2755.     mac_cleanup_tmpf();
  2756. #else
  2757.     cleanup_tmpf();
  2758. #endif
  2759.     /* Merge any entropy we collected into the randseed.bin file */
  2760.     if (cryptRandOpen((struct IdeaCfbContext *)0) >= 0)
  2761.         cryptRandSave((struct IdeaCfbContext *)0);
  2762. #if defined(DEBUG) && defined(linux)
  2763.     if (verbose) {
  2764.     struct mstats mstat;
  2765.     mstat = mstats();
  2766.     printf("%d chunks used (%d bytes)  %d bytes total\n",
  2767.            mstat.chunks_used, mstat.bytes_used, mstat.bytes_total);
  2768.     }
  2769. #endif
  2770.     memset(buf, 0, sizeof(buf));    /* wipe stack */
  2771. #ifdef VMS
  2772. /*
  2773.  * Fake VMS style error returns with severity in bottom 3 bits
  2774.  */
  2775.     if (returnval)
  2776.     returnval = (returnval << 3) | 0x10000002;
  2777.     else
  2778.     returnval = 0x10000001;
  2779. #endif                /* VMS */
  2780.     exit(returnval);
  2781. }
  2782.  
  2783. static void arg_error()
  2784. {
  2785.     signon_msg();
  2786.     fprintf(pgpout, LANG("\nInvalid arguments.\n"));
  2787.     errorLvl = BAD_ARG_ERROR;
  2788.     user_error();
  2789. }
  2790.  
  2791. /*
  2792.  * Check for language specific help files in PGPPATH, then the system
  2793.  * directory.  If that fails, check for the default pgp.hlp, again
  2794.  * first a private copy, then the system-wide one.
  2795.  *
  2796.  * System-wide copies currently only exist on Unix.
  2797.  */
  2798. static void build_helpfile(char *helpfile, char const *extra)
  2799. {
  2800.     if (strcmp(language, "en")) {
  2801.     buildfilename(helpfile, language);
  2802.     strcat(helpfile, extra);
  2803.     force_extension(helpfile, HLP_EXTENSION);
  2804.     if (file_exists(helpfile))
  2805.         return;
  2806. #ifdef PGP_SYSTEM_DIR
  2807.     strcpy(helpfile, PGP_SYSTEM_DIR);
  2808.     strcat(helpfile, language);
  2809.     strcat(helpfile, extra);
  2810.     force_extension(helpfile, HLP_EXTENSION);
  2811.     if (file_exists(helpfile))
  2812.         return;
  2813. #endif
  2814.     }
  2815.     buildfilename(helpfile, "pgp");
  2816.     strcat(helpfile, extra);
  2817.     force_extension(helpfile, HLP_EXTENSION);
  2818. #ifdef PGP_SYSTEM_DIR
  2819.     if (file_exists(helpfile))
  2820.     return;
  2821.     strcpy(helpfile, PGP_SYSTEM_DIR);
  2822.     strcat(helpfile, "pgp");
  2823.     strcat(helpfile, extra);
  2824.     force_extension(helpfile, HLP_EXTENSION);
  2825. #endif
  2826. }
  2827.  
  2828. static void usage()
  2829. {
  2830.     char helpfile[MAX_PATH];
  2831.     char *tmphelp = helpfile;
  2832.     extern unsigned char *ext_c_ptr;
  2833.  
  2834.     signon_msg();
  2835.     build_helpfile(helpfile, "");
  2836.  
  2837.     if (ext_c_ptr) {
  2838.     /* conversion to external format necessary */
  2839.     tmphelp = tempfile(TMP_TMPDIR);
  2840.     CONVERSION = EXT_CONV;
  2841.     if (copyfiles_by_name(helpfile, tmphelp) < 0) {
  2842.         rmtemp(tmphelp);
  2843.         tmphelp = helpfile;
  2844.     }
  2845.     CONVERSION = NO_CONV;
  2846.     }
  2847.     /* built-in help if pgp.hlp is not available */
  2848.     if (more_file(tmphelp, FALSE) < 0)
  2849.     fprintf(pgpout, LANG("\nUsage summary:\
  2850. \nTo encrypt a plaintext file with recipent's public key, type:\
  2851. \n   pgp -e textfile her_userid [other userids] (produces textfile.pgp)\
  2852. \nTo sign a plaintext file with your secret key:\
  2853. \n   pgp -s textfile [-u your_userid]           (produces textfile.pgp)\
  2854. \nTo sign a plaintext file with your secret key, and then encrypt it\
  2855. \n   with recipent's public key, producing a .pgp file:\
  2856. \n   pgp -es textfile her_userid [other userids] [-u your_userid]\
  2857. \nTo encrypt with conventional encryption only:\
  2858. \n   pgp -c textfile\
  2859. \nTo decrypt or check a signature for a ciphertext (.pgp) file:\
  2860. \n   pgp ciphertextfile [-o plaintextfile]\
  2861. \nTo produce output in ASCII for email, add the -a option to other options.\
  2862. \nTo generate your own unique public/secret key pair:  pgp -kg\
  2863. \nFor help on other key management functions, type:   pgp -k\n"));
  2864.     if (ext_c_ptr)
  2865.     rmtemp(tmphelp);
  2866.     exit(BAD_ARG_ERROR);    /* error exit */
  2867. }
  2868.  
  2869. static void key_usage()
  2870. {
  2871.     char helpfile[MAX_PATH];
  2872.     char *tmphelp = helpfile;
  2873.     extern unsigned char *ext_c_ptr;
  2874.  
  2875.     signon_msg();
  2876.     build_helpfile(helpfile, "key");
  2877.  
  2878.     if (ext_c_ptr) {
  2879.     /* conversion to external format necessary */
  2880.     tmphelp = tempfile(TMP_TMPDIR);
  2881.     CONVERSION = EXT_CONV;
  2882.     if (copyfiles_by_name(helpfile, tmphelp) < 0) {
  2883.         rmtemp(tmphelp);
  2884.         tmphelp = helpfile;
  2885.     }
  2886.     CONVERSION = NO_CONV;
  2887.     }
  2888.     /* built-in help if key.hlp is not available */
  2889.     if (more_file(tmphelp, FALSE) < 0)
  2890.     /* only use built-in help if there is no helpfile */
  2891.     fprintf(pgpout, LANG("\nKey management functions:\
  2892. \nTo generate your own unique public/secret key pair:\
  2893. \n   pgp -kg\
  2894. \nTo add a key file's contents to your public or secret key ring:\
  2895. \n   pgp -ka keyfile [keyring]\
  2896. \nTo remove a key or a user ID from your public or secret key ring:\
  2897. \n   pgp -kr userid [keyring]\
  2898. \nTo edit your user ID or pass phrase:\
  2899. \n   pgp -ke your_userid [keyring]\
  2900. \nTo extract (copy) a key from your public or secret key ring:\
  2901. \n   pgp -kx userid keyfile [keyring]\
  2902. \nTo view the contents of your public key ring:\
  2903. \n   pgp -kv[v] [userid] [keyring]\
  2904. \nTo check signatures on your public key ring:\
  2905. \n   pgp -kc [userid] [keyring]\
  2906. \nTo sign someone else's public key on your public key ring:\
  2907. \n   pgp -ks her_userid [-u your_userid] [keyring]\
  2908. \nTo remove selected signatures from a userid on a keyring:\
  2909. \n   pgp -krs userid [keyring]\
  2910. \n"));
  2911.     if (ext_c_ptr)
  2912.     rmtemp(tmphelp);
  2913.     exit(BAD_ARG_ERROR);    /* error exit */
  2914. }
  2915.  
  2916. char **ParseRecipients(char **recipients)
  2917. {
  2918.     /*
  2919.      * ParseRecipients() expects an array of pointers to
  2920.      * characters, usually the array returned by the C startup
  2921.      * code. Then it will look for entries beginning with the
  2922.        * string "-@" followed by a filename, which may be appended
  2923.       * directly or seperated by a blank.
  2924.       *
  2925.       * If the file exists and is readable, the routine will load
  2926.       * the contents and insert it into the command line as if the
  2927.       * names had been specified there.
  2928.       *
  2929.       * Each entry in the file consists of one line. The file line
  2930.       * will be treated as one argument, no matter whether it
  2931.       * contains spaces or not. Lines beginning with "#" will be
  2932.       * ignored and treated as comments. Empty lines will be ignored
  2933.       * also. Trailing white spaces will be removed.
  2934.       *
  2935.       * Currently, ParseRecipients() uses one fixed buffer, meaning,
  2936.       * that one single line must not be longer than 255 characters.
  2937.       * The number of included lines is unlimited.
  2938.       *
  2939.       * When any kind of problem occurs, PGP will terminate and do
  2940.       * nothing. No need to test for an error, the result is always
  2941.       * correct.
  2942.       *
  2943.        *             21-Sep-95, Peter Simons <simons@peti.rhein.de>
  2944.       */
  2945.  
  2946.     char **backup = recipients, **new;
  2947.     int entrynum;
  2948.      int MAX_RECIPIENTS = 128;   /* The name is somewhat wrong. of
  2949.                       * course the memory handling is
  2950.                       * dynamic.
  2951.                       */
  2952.  
  2953.      /* Check whether we need to do something or not. */
  2954.      while(*recipients) {
  2955.          if (!strncmp(*recipients, INCLUDE_MARK, INCLUDE_MARK_LEN))
  2956.              break;
  2957.          recipients++;
  2958.      }
  2959.      if (!*recipients)
  2960.        return backup;    /* nothin' happened */
  2961.  
  2962.      recipients=backup;
  2963.      if (!(new = malloc(MAX_RECIPIENTS * sizeof(char *))))
  2964.        exitPGP(OUT_OF_MEM);
  2965.      entrynum = 0;
  2966.  
  2967.      while(*recipients) {
  2968.          if (strncmp(*recipients, INCLUDE_MARK, INCLUDE_MARK_LEN))
  2969.                 {
  2970.              new[entrynum++] = *recipients++;
  2971.              if (entrynum == MAX_RECIPIENTS) {
  2972.                  /* Current buffer is too small.
  2973.                   * Use realloc() to largen itt.
  2974.                   */
  2975.                  MAX_RECIPIENTS += 128;
  2976.                  if (!(new = realloc(new,
  2977.                                  MAX_RECIPIENTS * sizeof(char *))))
  2978.                    exitPGP(OUT_OF_MEM);
  2979.              }
  2980.          }
  2981.          else {
  2982.              /* We got a hit! Load the file and parse it. */
  2983.              FILE *fh;
  2984.              char *filename, tempbuf[256];
  2985.  
  2986.              if (strlen(*recipients) == INCLUDE_MARK_LEN)
  2987.                filename = *++recipients;
  2988.              else
  2989.                filename = *recipients+INCLUDE_MARK_LEN;
  2990.              fprintf(pgpout, LANG("\nIncluding \"%s\"...\n"), filename);
  2991.              if (!(fh = fopen(filename, "r"))) {
  2992.                  perror("PGP");
  2993.                  exitPGP(UNKNOWN_FILE_ERROR);
  2994.              }
  2995.              while(fgets(tempbuf, sizeof(tempbuf)-1, fh)) {
  2996.                  int i = strlen(tempbuf);
  2997.  
  2998.                  /* Test for comments or empty lines. */
  2999.                  if (!i || *tempbuf == '#')
  3000.                    continue;
  3001.  
  3002.                  /* Remove trailing blanks. */
  3003.                  while (isspace(tempbuf[i-1]))
  3004.                    i--;
  3005.                  tempbuf[i] = '\0';
  3006.  
  3007.                  /* Copy new entry to new */
  3008.                  if (!(new[entrynum++] = store_str(tempbuf)))
  3009.                    exitPGP(OUT_OF_MEM);
  3010.                  if (entrynum == MAX_RECIPIENTS) {
  3011.                      /* Current buffer is too small.
  3012.                       * Use realloc() to largen itt.
  3013.                       */
  3014.                      MAX_RECIPIENTS += 128;
  3015.                      if (!(new = realloc(new,
  3016.                                          MAX_RECIPIENTS * sizeof(char *))))
  3017.                        exitPGP(OUT_OF_MEM);
  3018.                  }
  3019.              }
  3020.              if (ferror(fh)) {
  3021.                  perror("PGP");
  3022.                  exitPGP(UNKNOWN_FILE_ERROR);
  3023.              }
  3024.              fclose(fh);
  3025.              recipients++;
  3026.          }
  3027.      }
  3028.  
  3029.      /*
  3030.       * We have to write one trailing NULL pointer.
  3031.       * Check array size first.
  3032.       */
  3033.      if (entrynum == MAX_RECIPIENTS) {
  3034.          if (!(new = realloc(new, (MAX_RECIPIENTS+1) * sizeof(char *))))
  3035.            exitPGP(OUT_OF_MEM);
  3036.      }
  3037.      new[entrynum] = NULL;
  3038.      return new;
  3039. }
  3040.